mirror of
https://github.com/google/nomulus
synced 2026-05-24 08:41:48 +00:00
Compare commits
18 Commits
nomulus-20
...
nomulus-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d685f7e2df | ||
|
|
40eef2a06c | ||
|
|
8bd5eb4eca | ||
|
|
83918e92b5 | ||
|
|
5bba65835a | ||
|
|
1e51f51979 | ||
|
|
db2e896d42 | ||
|
|
478064f32b | ||
|
|
0db535b838 | ||
|
|
3705f37fab | ||
|
|
86bdd154bc | ||
|
|
576c05ff5f | ||
|
|
f52e887db5 | ||
|
|
6ed286e3bc | ||
|
|
93d922af6f | ||
|
|
0b73e9032c | ||
|
|
4d5d9700b8 | ||
|
|
3534a146e4 |
@@ -1,25 +1,28 @@
|
||||
# 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.
|
||||
com.github.ben-manes.caffeine:caffeine:2.7.0
|
||||
com.github.kevinstern:software-and-algorithms:1.0
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.google.auto.value:auto-value:1.6.3
|
||||
com.google.auto:auto-common:0.10
|
||||
com.google.code.findbugs:jFormatString:3.0.0
|
||||
com.google.code.findbugs:jsr305:3.0.2
|
||||
com.google.errorprone:error_prone_annotation:2.3.3
|
||||
com.google.errorprone:error_prone_annotations:2.3.3
|
||||
com.google.errorprone:error_prone_check_api:2.3.3
|
||||
com.google.errorprone:error_prone_core:2.3.3
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.3
|
||||
com.google.errorprone:error_prone_annotation:2.3.4
|
||||
com.google.errorprone:error_prone_annotations:2.3.4
|
||||
com.google.errorprone:error_prone_check_api:2.3.4
|
||||
com.google.errorprone:error_prone_core:2.3.4
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.4
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:27.0.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.j2objc:j2objc-annotations:1.1
|
||||
com.google.protobuf:protobuf-java:3.4.0
|
||||
com.googlecode.java-diff-utils:diffutils:1.3.0
|
||||
org.checkerframework:checker-qual:2.5.3
|
||||
org.checkerframework:dataflow:2.5.3
|
||||
org.checkerframework:javacutil:2.5.3
|
||||
org.checkerframework:checker-qual:3.0.0
|
||||
org.checkerframework:dataflow:3.0.0
|
||||
org.checkerframework:javacutil:3.0.0
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.pcollections:pcollections:2.1.2
|
||||
org.plumelib:plume-util:1.0.6
|
||||
org.plumelib:reflection-util:0.0.2
|
||||
org.plumelib:require-javadoc:0.1.0
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
# 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.
|
||||
com.github.ben-manes.caffeine:caffeine:2.7.0
|
||||
com.github.kevinstern:software-and-algorithms:1.0
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.google.auto:auto-common:0.10
|
||||
com.google.code.findbugs:jFormatString:3.0.0
|
||||
com.google.code.findbugs:jsr305:3.0.2
|
||||
com.google.errorprone:error_prone_annotation:2.3.3
|
||||
com.google.errorprone:error_prone_annotations:2.3.3
|
||||
com.google.errorprone:error_prone_check_api:2.3.3
|
||||
com.google.errorprone:error_prone_core:2.3.3
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.3
|
||||
com.google.errorprone:error_prone_annotation:2.3.4
|
||||
com.google.errorprone:error_prone_annotations:2.3.4
|
||||
com.google.errorprone:error_prone_check_api:2.3.4
|
||||
com.google.errorprone:error_prone_core:2.3.4
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.4
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:27.0.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.j2objc:j2objc-annotations:1.1
|
||||
com.google.protobuf:protobuf-java:3.4.0
|
||||
com.googlecode.java-diff-utils:diffutils:1.3.0
|
||||
org.checkerframework:checker-qual:2.5.3
|
||||
org.checkerframework:dataflow:2.5.3
|
||||
org.checkerframework:javacutil:2.5.3
|
||||
org.checkerframework:checker-qual:3.0.0
|
||||
org.checkerframework:dataflow:3.0.0
|
||||
org.checkerframework:javacutil:3.0.0
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.pcollections:pcollections:2.1.2
|
||||
org.plumelib:plume-util:1.0.6
|
||||
org.plumelib:reflection-util:0.0.2
|
||||
org.plumelib:require-javadoc:0.1.0
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
# 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.
|
||||
com.github.ben-manes.caffeine:caffeine:2.7.0
|
||||
com.github.kevinstern:software-and-algorithms:1.0
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.google.auto:auto-common:0.10
|
||||
com.google.code.findbugs:jFormatString:3.0.0
|
||||
com.google.code.findbugs:jsr305:3.0.2
|
||||
com.google.errorprone:error_prone_annotation:2.3.3
|
||||
com.google.errorprone:error_prone_annotations:2.3.3
|
||||
com.google.errorprone:error_prone_check_api:2.3.3
|
||||
com.google.errorprone:error_prone_core:2.3.3
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.3
|
||||
com.google.errorprone:error_prone_annotation:2.3.4
|
||||
com.google.errorprone:error_prone_annotations:2.3.4
|
||||
com.google.errorprone:error_prone_check_api:2.3.4
|
||||
com.google.errorprone:error_prone_core:2.3.4
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.4
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:27.0.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.j2objc:j2objc-annotations:1.1
|
||||
com.google.protobuf:protobuf-java:3.4.0
|
||||
com.googlecode.java-diff-utils:diffutils:1.3.0
|
||||
org.checkerframework:checker-qual:2.5.3
|
||||
org.checkerframework:dataflow:2.5.3
|
||||
org.checkerframework:javacutil:2.5.3
|
||||
org.checkerframework:checker-qual:3.0.0
|
||||
org.checkerframework:dataflow:3.0.0
|
||||
org.checkerframework:javacutil:3.0.0
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.pcollections:pcollections:2.1.2
|
||||
org.plumelib:plume-util:1.0.6
|
||||
org.plumelib:reflection-util:0.0.2
|
||||
org.plumelib:require-javadoc:0.1.0
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
# 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.
|
||||
com.github.ben-manes.caffeine:caffeine:2.7.0
|
||||
com.github.kevinstern:software-and-algorithms:1.0
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.google.auto:auto-common:0.10
|
||||
com.google.code.findbugs:jFormatString:3.0.0
|
||||
com.google.code.findbugs:jsr305:3.0.2
|
||||
com.google.errorprone:error_prone_annotation:2.3.3
|
||||
com.google.errorprone:error_prone_annotations:2.3.3
|
||||
com.google.errorprone:error_prone_check_api:2.3.3
|
||||
com.google.errorprone:error_prone_core:2.3.3
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.3
|
||||
com.google.errorprone:error_prone_annotation:2.3.4
|
||||
com.google.errorprone:error_prone_annotations:2.3.4
|
||||
com.google.errorprone:error_prone_check_api:2.3.4
|
||||
com.google.errorprone:error_prone_core:2.3.4
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.4
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:27.0.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.j2objc:j2objc-annotations:1.1
|
||||
com.google.protobuf:protobuf-java:3.4.0
|
||||
com.googlecode.java-diff-utils:diffutils:1.3.0
|
||||
org.checkerframework:checker-qual:2.5.3
|
||||
org.checkerframework:dataflow:2.5.3
|
||||
org.checkerframework:javacutil:2.5.3
|
||||
org.checkerframework:checker-qual:3.0.0
|
||||
org.checkerframework:dataflow:3.0.0
|
||||
org.checkerframework:javacutil:3.0.0
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.pcollections:pcollections:2.1.2
|
||||
org.plumelib:plume-util:1.0.6
|
||||
org.plumelib:reflection-util:0.0.2
|
||||
org.plumelib:require-javadoc:0.1.0
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
# 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.
|
||||
com.github.ben-manes.caffeine:caffeine:2.7.0
|
||||
com.github.kevinstern:software-and-algorithms:1.0
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.google.auto:auto-common:0.10
|
||||
com.google.code.findbugs:jFormatString:3.0.0
|
||||
com.google.code.findbugs:jsr305:3.0.2
|
||||
com.google.errorprone:error_prone_annotation:2.3.3
|
||||
com.google.errorprone:error_prone_annotations:2.3.3
|
||||
com.google.errorprone:error_prone_check_api:2.3.3
|
||||
com.google.errorprone:error_prone_core:2.3.3
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.3
|
||||
com.google.errorprone:error_prone_annotation:2.3.4
|
||||
com.google.errorprone:error_prone_annotations:2.3.4
|
||||
com.google.errorprone:error_prone_check_api:2.3.4
|
||||
com.google.errorprone:error_prone_core:2.3.4
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.4
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:27.0.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.j2objc:j2objc-annotations:1.1
|
||||
com.google.protobuf:protobuf-java:3.4.0
|
||||
com.googlecode.java-diff-utils:diffutils:1.3.0
|
||||
org.checkerframework:checker-qual:2.5.3
|
||||
org.checkerframework:dataflow:2.5.3
|
||||
org.checkerframework:javacutil:2.5.3
|
||||
org.checkerframework:checker-qual:3.0.0
|
||||
org.checkerframework:dataflow:3.0.0
|
||||
org.checkerframework:javacutil:3.0.0
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.pcollections:pcollections:2.1.2
|
||||
org.plumelib:plume-util:1.0.6
|
||||
org.plumelib:reflection-util:0.0.2
|
||||
org.plumelib:require-javadoc:0.1.0
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
# 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.
|
||||
com.github.ben-manes.caffeine:caffeine:2.7.0
|
||||
com.github.kevinstern:software-and-algorithms:1.0
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.google.auto:auto-common:0.10
|
||||
com.google.code.findbugs:jFormatString:3.0.0
|
||||
com.google.code.findbugs:jsr305:3.0.2
|
||||
com.google.errorprone:error_prone_annotation:2.3.3
|
||||
com.google.errorprone:error_prone_annotations:2.3.3
|
||||
com.google.errorprone:error_prone_check_api:2.3.3
|
||||
com.google.errorprone:error_prone_core:2.3.3
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.3
|
||||
com.google.errorprone:error_prone_annotation:2.3.4
|
||||
com.google.errorprone:error_prone_annotations:2.3.4
|
||||
com.google.errorprone:error_prone_check_api:2.3.4
|
||||
com.google.errorprone:error_prone_core:2.3.4
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.4
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:27.0.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.j2objc:j2objc-annotations:1.1
|
||||
com.google.protobuf:protobuf-java:3.4.0
|
||||
com.googlecode.java-diff-utils:diffutils:1.3.0
|
||||
org.checkerframework:checker-qual:2.5.3
|
||||
org.checkerframework:dataflow:2.5.3
|
||||
org.checkerframework:javacutil:2.5.3
|
||||
org.checkerframework:checker-qual:3.0.0
|
||||
org.checkerframework:dataflow:3.0.0
|
||||
org.checkerframework:javacutil:3.0.0
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.pcollections:pcollections:2.1.2
|
||||
org.plumelib:plume-util:1.0.6
|
||||
org.plumelib:reflection-util:0.0.2
|
||||
org.plumelib:require-javadoc:0.1.0
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.time.ZonedDateTime;
|
||||
import java.util.TimeZone;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
/** Utilities methods and constants related to Joda {@link DateTime} objects. */
|
||||
public class DateTimeUtils {
|
||||
@@ -108,4 +109,12 @@ public class DateTimeUtils {
|
||||
zonedDateTime.toInstant().toEpochMilli(),
|
||||
DateTimeZone.forTimeZone(TimeZone.getTimeZone(zonedDateTime.getZone())));
|
||||
}
|
||||
|
||||
public static java.sql.Date toSqlDate(LocalDate localDate) {
|
||||
return new java.sql.Date(localDate.toDateTimeAtStartOfDay().getMillis());
|
||||
}
|
||||
|
||||
public static LocalDate toLocalDate(java.sql.Date date) {
|
||||
return new LocalDate(date.getTime(), DateTimeZone.UTC);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import com.google.common.util.concurrent.Uninterruptibles;
|
||||
import java.io.Serializable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.ReadableDuration;
|
||||
@@ -41,6 +40,6 @@ public final class SystemSleeper implements Sleeper, Serializable {
|
||||
@Override
|
||||
public void sleepUninterruptibly(ReadableDuration duration) {
|
||||
checkArgument(duration.getMillis() >= 0);
|
||||
Uninterruptibles.sleepUninterruptibly(duration.getMillis(), TimeUnit.MILLISECONDS);
|
||||
Uninterruptibles.sleepUninterruptibly(java.time.Duration.ofMillis(duration.getMillis()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,6 +221,7 @@ dependencies {
|
||||
compile deps['com.jcraft:jsch']
|
||||
testCompile deps['com.thoughtworks.qdox:qdox']
|
||||
compile deps['dnsjava:dnsjava']
|
||||
runtime deps['guru.nidi:graphviz-java-all-j2v8']
|
||||
testCompile deps['io.github.classgraph:classgraph']
|
||||
testRuntime deps['io.github.java-diff-utils:java-diff-utils']
|
||||
testCompile deps['javax.annotation:javax.annotation-api']
|
||||
@@ -258,6 +259,7 @@ dependencies {
|
||||
compile deps['org.hibernate:hibernate-core']
|
||||
compile deps['org.joda:joda-money']
|
||||
compile deps['org.json:json']
|
||||
compile deps['org.jsoup:jsoup']
|
||||
testCompile deps['org.mortbay.jetty:jetty']
|
||||
compile deps['org.postgresql:postgresql']
|
||||
testCompile deps['org.seleniumhq.selenium:selenium-api']
|
||||
@@ -271,7 +273,9 @@ dependencies {
|
||||
testCompile deps['org.testcontainers:selenium']
|
||||
testCompile deps['org.testcontainers:testcontainers']
|
||||
compile deps['us.fatehi:schemacrawler']
|
||||
compile deps['us.fatehi:schemacrawler-api']
|
||||
compile deps['us.fatehi:schemacrawler-diagram']
|
||||
compile deps['us.fatehi:schemacrawler-tools']
|
||||
compile deps['xerces:xmlParserAPIs']
|
||||
compile deps['xpp3:xpp3']
|
||||
// This dependency must come after javax.mail:mail as it would otherwise
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# 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.
|
||||
com.github.ben-manes.caffeine:caffeine:2.7.0
|
||||
com.github.kevinstern:software-and-algorithms:1.0
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.google.auto.value:auto-value:1.6.3
|
||||
com.google.auto:auto-common:0.10
|
||||
com.google.code.findbugs:jFormatString:3.0.0
|
||||
@@ -11,11 +11,11 @@ com.google.dagger:dagger-compiler:2.28
|
||||
com.google.dagger:dagger-producers:2.28
|
||||
com.google.dagger:dagger-spi:2.28
|
||||
com.google.dagger:dagger:2.28
|
||||
com.google.errorprone:error_prone_annotation:2.3.3
|
||||
com.google.errorprone:error_prone_annotation:2.3.4
|
||||
com.google.errorprone:error_prone_annotations:2.3.4
|
||||
com.google.errorprone:error_prone_check_api:2.3.3
|
||||
com.google.errorprone:error_prone_core:2.3.3
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.3
|
||||
com.google.errorprone:error_prone_check_api:2.3.4
|
||||
com.google.errorprone:error_prone_core:2.3.4
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.4
|
||||
com.google.errorprone:javac-shaded:9-dev-r4023-3
|
||||
com.google.googlejavaformat:google-java-format:1.5
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
@@ -30,11 +30,14 @@ javax.inject:javax.inject:1
|
||||
javax.persistence:javax.persistence-api:2.2
|
||||
net.ltgt.gradle.incap:incap:0.2
|
||||
org.checkerframework:checker-compat-qual:2.5.3
|
||||
org.checkerframework:checker-qual:2.11.1
|
||||
org.checkerframework:dataflow:2.5.3
|
||||
org.checkerframework:javacutil:2.5.3
|
||||
org.checkerframework:checker-qual:3.0.0
|
||||
org.checkerframework:dataflow:3.0.0
|
||||
org.checkerframework:javacutil:3.0.0
|
||||
org.jetbrains.kotlin:kotlin-stdlib-common:1.3.61
|
||||
org.jetbrains.kotlin:kotlin-stdlib:1.3.61
|
||||
org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.1.0
|
||||
org.jetbrains:annotations:13.0
|
||||
org.pcollections:pcollections:2.1.2
|
||||
org.plumelib:plume-util:1.0.6
|
||||
org.plumelib:reflection-util:0.0.2
|
||||
org.plumelib:require-javadoc:0.1.0
|
||||
|
||||
@@ -226,6 +226,7 @@ org.jboss:jandex:2.1.3.Final
|
||||
org.jetbrains:annotations:19.0.0
|
||||
org.joda:joda-money:1.0.1
|
||||
org.json:json:20160810
|
||||
org.jsoup:jsoup:1.13.1
|
||||
org.jvnet.staxex:stax-ex:1.8
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
|
||||
@@ -223,6 +223,7 @@ org.jboss:jandex:2.1.3.Final
|
||||
org.jetbrains:annotations:19.0.0
|
||||
org.joda:joda-money:1.0.1
|
||||
org.json:json:20160810
|
||||
org.jsoup:jsoup:1.13.1
|
||||
org.jvnet.staxex:stax-ex:1.8
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
|
||||
@@ -6,6 +6,10 @@ aopalliance:aopalliance:1.0
|
||||
args4j:args4j:2.33
|
||||
cglib:cglib-nodep:2.2
|
||||
com.beust:jcommander:1.60
|
||||
com.eclipsesource.j2v8:j2v8_linux_x86_64:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_macosx_x86_64:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_win32_x86:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_win32_x86_64:4.6.0
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.10.2
|
||||
com.fasterxml.jackson.core:jackson-core:2.10.2
|
||||
com.fasterxml.jackson.core:jackson-databind:2.10.2
|
||||
@@ -130,6 +134,9 @@ com.zaxxer:HikariCP:3.2.0
|
||||
commons-codec:commons-codec:1.13
|
||||
commons-logging:commons-logging:1.2
|
||||
dnsjava:dnsjava:2.1.7
|
||||
guru.nidi.com.kitfox:svgSalamander:1.1.3
|
||||
guru.nidi:graphviz-java-all-j2v8:0.17.0
|
||||
guru.nidi:graphviz-java:0.17.0
|
||||
io.dropwizard.metrics:metrics-core:3.2.6
|
||||
io.github.classgraph:classgraph:4.8.65
|
||||
io.grpc:grpc-all:1.27.2
|
||||
@@ -177,6 +184,7 @@ javax.xml.bind:jaxb-api:2.3.1
|
||||
jline:jline:1.0
|
||||
joda-time:joda-time:2.10.5
|
||||
junit:junit:4.12
|
||||
net.arnx:nashorn-promise:0.1.1
|
||||
net.bytebuddy:byte-buddy:1.10.10
|
||||
net.java.dev.jna:jna-platform:5.5.0
|
||||
net.java.dev.jna:jna:5.5.0
|
||||
@@ -198,6 +206,7 @@ org.apache.beam:beam-vendor-grpc-1_26_0:0.3
|
||||
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
|
||||
org.apache.beam:beam-vendor-sdks-java-extensions-protobuf:2.23.0
|
||||
org.apache.commons:commons-compress:1.20
|
||||
org.apache.commons:commons-exec:1.3
|
||||
org.apache.commons:commons-lang3:3.5
|
||||
org.apache.httpcomponents:httpclient:4.5.11
|
||||
org.apache.httpcomponents:httpcore:4.4.13
|
||||
@@ -228,6 +237,7 @@ org.jboss:jandex:2.1.3.Final
|
||||
org.jetbrains:annotations:19.0.0
|
||||
org.joda:joda-money:1.0.1
|
||||
org.json:json:20160810
|
||||
org.jsoup:jsoup:1.13.1
|
||||
org.jvnet.staxex:stax-ex:1.8
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
@@ -242,6 +252,8 @@ org.rnorth.duct-tape:duct-tape:1.0.8
|
||||
org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
org.rnorth:tcp-unix-socket-proxy:1.0.2
|
||||
org.scijava:native-lib-loader:2.0.2
|
||||
org.slf4j:jcl-over-slf4j:1.7.30
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.slf4j:slf4j-jdk14:1.7.28
|
||||
org.testcontainers:database-commons:1.14.3
|
||||
@@ -251,6 +263,7 @@ org.testcontainers:testcontainers:1.14.3
|
||||
org.threeten:threetenbp:1.4.1
|
||||
org.tukaani:xz:1.8
|
||||
org.w3c.css:sac:1.3
|
||||
org.webjars.npm:viz.js-for-graphviz-java:2.1.3
|
||||
org.xerial.snappy:snappy-java:1.1.4
|
||||
org.yaml:snakeyaml:1.17
|
||||
us.fatehi:schemacrawler-api:16.10.1
|
||||
|
||||
@@ -6,6 +6,10 @@ aopalliance:aopalliance:1.0
|
||||
args4j:args4j:2.33
|
||||
cglib:cglib-nodep:2.2
|
||||
com.beust:jcommander:1.60
|
||||
com.eclipsesource.j2v8:j2v8_linux_x86_64:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_macosx_x86_64:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_win32_x86:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_win32_x86_64:4.6.0
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.10.2
|
||||
com.fasterxml.jackson.core:jackson-core:2.10.2
|
||||
com.fasterxml.jackson.core:jackson-databind:2.10.2
|
||||
@@ -130,6 +134,9 @@ com.zaxxer:HikariCP:3.2.0
|
||||
commons-codec:commons-codec:1.13
|
||||
commons-logging:commons-logging:1.2
|
||||
dnsjava:dnsjava:2.1.7
|
||||
guru.nidi.com.kitfox:svgSalamander:1.1.3
|
||||
guru.nidi:graphviz-java-all-j2v8:0.17.0
|
||||
guru.nidi:graphviz-java:0.17.0
|
||||
io.dropwizard.metrics:metrics-core:3.2.6
|
||||
io.github.classgraph:classgraph:4.8.65
|
||||
io.grpc:grpc-all:1.27.2
|
||||
@@ -176,6 +183,7 @@ javax.validation:validation-api:1.0.0.GA
|
||||
javax.xml.bind:jaxb-api:2.3.1
|
||||
jline:jline:1.0
|
||||
joda-time:joda-time:2.10.5
|
||||
net.arnx:nashorn-promise:0.1.1
|
||||
net.bytebuddy:byte-buddy:1.10.10
|
||||
net.java.dev.jna:jna-platform:5.5.0
|
||||
net.java.dev.jna:jna:5.5.0
|
||||
@@ -197,6 +205,7 @@ org.apache.beam:beam-vendor-grpc-1_26_0:0.3
|
||||
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
|
||||
org.apache.beam:beam-vendor-sdks-java-extensions-protobuf:2.23.0
|
||||
org.apache.commons:commons-compress:1.20
|
||||
org.apache.commons:commons-exec:1.3
|
||||
org.apache.commons:commons-lang3:3.5
|
||||
org.apache.httpcomponents:httpclient:4.5.11
|
||||
org.apache.httpcomponents:httpcore:4.4.13
|
||||
@@ -226,6 +235,7 @@ org.jboss:jandex:2.1.3.Final
|
||||
org.jetbrains:annotations:19.0.0
|
||||
org.joda:joda-money:1.0.1
|
||||
org.json:json:20160810
|
||||
org.jsoup:jsoup:1.13.1
|
||||
org.jvnet.staxex:stax-ex:1.8
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
@@ -240,6 +250,8 @@ org.rnorth.duct-tape:duct-tape:1.0.8
|
||||
org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
org.rnorth:tcp-unix-socket-proxy:1.0.2
|
||||
org.scijava:native-lib-loader:2.0.2
|
||||
org.slf4j:jcl-over-slf4j:1.7.30
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.slf4j:slf4j-jdk14:1.7.28
|
||||
org.testcontainers:database-commons:1.14.3
|
||||
@@ -249,6 +261,7 @@ org.testcontainers:testcontainers:1.14.3
|
||||
org.threeten:threetenbp:1.4.1
|
||||
org.tukaani:xz:1.8
|
||||
org.w3c.css:sac:1.3
|
||||
org.webjars.npm:viz.js-for-graphviz-java:2.1.3
|
||||
org.xerial.snappy:snappy-java:1.1.4
|
||||
org.yaml:snakeyaml:1.17
|
||||
us.fatehi:schemacrawler-api:16.10.1
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
# 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.
|
||||
com.github.ben-manes.caffeine:caffeine:2.7.0
|
||||
com.github.kevinstern:software-and-algorithms:1.0
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.google.auto:auto-common:0.10
|
||||
com.google.code.findbugs:jFormatString:3.0.0
|
||||
com.google.code.findbugs:jsr305:3.0.2
|
||||
com.google.errorprone:error_prone_annotation:2.3.3
|
||||
com.google.errorprone:error_prone_annotations:2.3.3
|
||||
com.google.errorprone:error_prone_check_api:2.3.3
|
||||
com.google.errorprone:error_prone_core:2.3.3
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.3
|
||||
com.google.errorprone:error_prone_annotation:2.3.4
|
||||
com.google.errorprone:error_prone_annotations:2.3.4
|
||||
com.google.errorprone:error_prone_check_api:2.3.4
|
||||
com.google.errorprone:error_prone_core:2.3.4
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.4
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:27.0.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.j2objc:j2objc-annotations:1.1
|
||||
com.google.protobuf:protobuf-java:3.4.0
|
||||
com.googlecode.java-diff-utils:diffutils:1.3.0
|
||||
org.checkerframework:checker-qual:2.5.3
|
||||
org.checkerframework:dataflow:2.5.3
|
||||
org.checkerframework:javacutil:2.5.3
|
||||
org.checkerframework:checker-qual:3.0.0
|
||||
org.checkerframework:dataflow:3.0.0
|
||||
org.checkerframework:javacutil:3.0.0
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.pcollections:pcollections:2.1.2
|
||||
org.plumelib:plume-util:1.0.6
|
||||
org.plumelib:reflection-util:0.0.2
|
||||
org.plumelib:require-javadoc:0.1.0
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
# 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.
|
||||
com.github.ben-manes.caffeine:caffeine:2.7.0
|
||||
com.github.kevinstern:software-and-algorithms:1.0
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.google.auto:auto-common:0.10
|
||||
com.google.code.findbugs:jFormatString:3.0.0
|
||||
com.google.code.findbugs:jsr305:3.0.2
|
||||
com.google.errorprone:error_prone_annotation:2.3.3
|
||||
com.google.errorprone:error_prone_annotations:2.3.3
|
||||
com.google.errorprone:error_prone_check_api:2.3.3
|
||||
com.google.errorprone:error_prone_core:2.3.3
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.3
|
||||
com.google.errorprone:error_prone_annotation:2.3.4
|
||||
com.google.errorprone:error_prone_annotations:2.3.4
|
||||
com.google.errorprone:error_prone_check_api:2.3.4
|
||||
com.google.errorprone:error_prone_core:2.3.4
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.4
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:27.0.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.j2objc:j2objc-annotations:1.1
|
||||
com.google.protobuf:protobuf-java:3.4.0
|
||||
com.googlecode.java-diff-utils:diffutils:1.3.0
|
||||
org.checkerframework:checker-qual:2.5.3
|
||||
org.checkerframework:dataflow:2.5.3
|
||||
org.checkerframework:javacutil:2.5.3
|
||||
org.checkerframework:checker-qual:3.0.0
|
||||
org.checkerframework:dataflow:3.0.0
|
||||
org.checkerframework:javacutil:3.0.0
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.pcollections:pcollections:2.1.2
|
||||
org.plumelib:plume-util:1.0.6
|
||||
org.plumelib:reflection-util:0.0.2
|
||||
org.plumelib:require-javadoc:0.1.0
|
||||
|
||||
@@ -226,6 +226,7 @@ org.jboss:jandex:2.1.3.Final
|
||||
org.jetbrains:annotations:19.0.0
|
||||
org.joda:joda-money:1.0.1
|
||||
org.json:json:20160810
|
||||
org.jsoup:jsoup:1.13.1
|
||||
org.jvnet.staxex:stax-ex:1.8
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
|
||||
@@ -225,6 +225,7 @@ org.jboss:jandex:2.1.3.Final
|
||||
org.jetbrains:annotations:19.0.0
|
||||
org.joda:joda-money:1.0.1
|
||||
org.json:json:20160810
|
||||
org.jsoup:jsoup:1.13.1
|
||||
org.jvnet.staxex:stax-ex:1.8
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
|
||||
@@ -6,6 +6,10 @@ aopalliance:aopalliance:1.0
|
||||
args4j:args4j:2.33
|
||||
cglib:cglib-nodep:2.2
|
||||
com.beust:jcommander:1.60
|
||||
com.eclipsesource.j2v8:j2v8_linux_x86_64:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_macosx_x86_64:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_win32_x86:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_win32_x86_64:4.6.0
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.10.2
|
||||
com.fasterxml.jackson.core:jackson-core:2.10.2
|
||||
com.fasterxml.jackson.core:jackson-databind:2.10.2
|
||||
@@ -129,6 +133,9 @@ com.zaxxer:HikariCP:3.2.0
|
||||
commons-codec:commons-codec:1.13
|
||||
commons-logging:commons-logging:1.2
|
||||
dnsjava:dnsjava:2.1.7
|
||||
guru.nidi.com.kitfox:svgSalamander:1.1.3
|
||||
guru.nidi:graphviz-java-all-j2v8:0.17.0
|
||||
guru.nidi:graphviz-java:0.17.0
|
||||
io.dropwizard.metrics:metrics-core:3.2.6
|
||||
io.github.classgraph:classgraph:4.8.65
|
||||
io.grpc:grpc-all:1.27.2
|
||||
@@ -176,6 +183,7 @@ javax.xml.bind:jaxb-api:2.3.1
|
||||
jline:jline:1.0
|
||||
joda-time:joda-time:2.10.5
|
||||
junit:junit:4.12
|
||||
net.arnx:nashorn-promise:0.1.1
|
||||
net.bytebuddy:byte-buddy:1.10.10
|
||||
net.java.dev.jna:jna-platform:5.5.0
|
||||
net.java.dev.jna:jna:5.5.0
|
||||
@@ -197,6 +205,7 @@ org.apache.beam:beam-vendor-grpc-1_26_0:0.3
|
||||
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
|
||||
org.apache.beam:beam-vendor-sdks-java-extensions-protobuf:2.23.0
|
||||
org.apache.commons:commons-compress:1.20
|
||||
org.apache.commons:commons-exec:1.3
|
||||
org.apache.commons:commons-lang3:3.5
|
||||
org.apache.httpcomponents:httpclient:4.5.11
|
||||
org.apache.httpcomponents:httpcore:4.4.13
|
||||
@@ -227,6 +236,7 @@ org.jboss:jandex:2.1.3.Final
|
||||
org.jetbrains:annotations:19.0.0
|
||||
org.joda:joda-money:1.0.1
|
||||
org.json:json:20160810
|
||||
org.jsoup:jsoup:1.13.1
|
||||
org.jvnet.staxex:stax-ex:1.8
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
@@ -241,6 +251,8 @@ org.rnorth.duct-tape:duct-tape:1.0.8
|
||||
org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
org.rnorth:tcp-unix-socket-proxy:1.0.2
|
||||
org.scijava:native-lib-loader:2.0.2
|
||||
org.slf4j:jcl-over-slf4j:1.7.30
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.testcontainers:database-commons:1.14.3
|
||||
org.testcontainers:jdbc:1.14.3
|
||||
@@ -249,6 +261,7 @@ org.testcontainers:testcontainers:1.14.3
|
||||
org.threeten:threetenbp:1.4.1
|
||||
org.tukaani:xz:1.8
|
||||
org.w3c.css:sac:1.3
|
||||
org.webjars.npm:viz.js-for-graphviz-java:2.1.3
|
||||
org.xerial.snappy:snappy-java:1.1.4
|
||||
org.yaml:snakeyaml:1.17
|
||||
us.fatehi:schemacrawler-api:16.10.1
|
||||
|
||||
@@ -6,6 +6,10 @@ aopalliance:aopalliance:1.0
|
||||
args4j:args4j:2.33
|
||||
cglib:cglib-nodep:2.2
|
||||
com.beust:jcommander:1.60
|
||||
com.eclipsesource.j2v8:j2v8_linux_x86_64:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_macosx_x86_64:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_win32_x86:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_win32_x86_64:4.6.0
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.10.2
|
||||
com.fasterxml.jackson.core:jackson-core:2.10.2
|
||||
com.fasterxml.jackson.core:jackson-databind:2.10.2
|
||||
@@ -129,6 +133,9 @@ com.zaxxer:HikariCP:3.2.0
|
||||
commons-codec:commons-codec:1.13
|
||||
commons-logging:commons-logging:1.2
|
||||
dnsjava:dnsjava:2.1.7
|
||||
guru.nidi.com.kitfox:svgSalamander:1.1.3
|
||||
guru.nidi:graphviz-java-all-j2v8:0.17.0
|
||||
guru.nidi:graphviz-java:0.17.0
|
||||
io.dropwizard.metrics:metrics-core:3.2.6
|
||||
io.github.classgraph:classgraph:4.8.65
|
||||
io.grpc:grpc-all:1.27.2
|
||||
@@ -176,6 +183,7 @@ javax.xml.bind:jaxb-api:2.3.1
|
||||
jline:jline:1.0
|
||||
joda-time:joda-time:2.10.5
|
||||
junit:junit:4.12
|
||||
net.arnx:nashorn-promise:0.1.1
|
||||
net.bytebuddy:byte-buddy:1.10.10
|
||||
net.java.dev.jna:jna-platform:5.5.0
|
||||
net.java.dev.jna:jna:5.5.0
|
||||
@@ -197,6 +205,7 @@ org.apache.beam:beam-vendor-grpc-1_26_0:0.3
|
||||
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
|
||||
org.apache.beam:beam-vendor-sdks-java-extensions-protobuf:2.23.0
|
||||
org.apache.commons:commons-compress:1.20
|
||||
org.apache.commons:commons-exec:1.3
|
||||
org.apache.commons:commons-lang3:3.5
|
||||
org.apache.httpcomponents:httpclient:4.5.11
|
||||
org.apache.httpcomponents:httpcore:4.4.13
|
||||
@@ -227,6 +236,7 @@ org.jboss:jandex:2.1.3.Final
|
||||
org.jetbrains:annotations:19.0.0
|
||||
org.joda:joda-money:1.0.1
|
||||
org.json:json:20160810
|
||||
org.jsoup:jsoup:1.13.1
|
||||
org.jvnet.staxex:stax-ex:1.8
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
@@ -241,6 +251,8 @@ org.rnorth.duct-tape:duct-tape:1.0.8
|
||||
org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
org.rnorth:tcp-unix-socket-proxy:1.0.2
|
||||
org.scijava:native-lib-loader:2.0.2
|
||||
org.slf4j:jcl-over-slf4j:1.7.30
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.testcontainers:database-commons:1.14.3
|
||||
org.testcontainers:jdbc:1.14.3
|
||||
@@ -249,6 +261,7 @@ org.testcontainers:testcontainers:1.14.3
|
||||
org.threeten:threetenbp:1.4.1
|
||||
org.tukaani:xz:1.8
|
||||
org.w3c.css:sac:1.3
|
||||
org.webjars.npm:viz.js-for-graphviz-java:2.1.3
|
||||
org.xerial.snappy:snappy-java:1.1.4
|
||||
org.yaml:snakeyaml:1.17
|
||||
us.fatehi:schemacrawler-api:16.10.1
|
||||
|
||||
@@ -6,6 +6,10 @@ aopalliance:aopalliance:1.0
|
||||
args4j:args4j:2.33
|
||||
cglib:cglib-nodep:2.2
|
||||
com.beust:jcommander:1.60
|
||||
com.eclipsesource.j2v8:j2v8_linux_x86_64:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_macosx_x86_64:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_win32_x86:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_win32_x86_64:4.6.0
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.10.2
|
||||
com.fasterxml.jackson.core:jackson-core:2.10.2
|
||||
com.fasterxml.jackson.core:jackson-databind:2.10.2
|
||||
@@ -129,6 +133,9 @@ com.zaxxer:HikariCP:3.2.0
|
||||
commons-codec:commons-codec:1.13
|
||||
commons-logging:commons-logging:1.2
|
||||
dnsjava:dnsjava:2.1.7
|
||||
guru.nidi.com.kitfox:svgSalamander:1.1.3
|
||||
guru.nidi:graphviz-java-all-j2v8:0.17.0
|
||||
guru.nidi:graphviz-java:0.17.0
|
||||
io.dropwizard.metrics:metrics-core:3.2.6
|
||||
io.github.classgraph:classgraph:4.8.65
|
||||
io.grpc:grpc-all:1.27.2
|
||||
@@ -176,6 +183,7 @@ javax.xml.bind:jaxb-api:2.3.1
|
||||
jline:jline:1.0
|
||||
joda-time:joda-time:2.10.5
|
||||
junit:junit:4.12
|
||||
net.arnx:nashorn-promise:0.1.1
|
||||
net.bytebuddy:byte-buddy:1.10.10
|
||||
net.java.dev.jna:jna-platform:5.5.0
|
||||
net.java.dev.jna:jna:5.5.0
|
||||
@@ -197,6 +205,7 @@ org.apache.beam:beam-vendor-grpc-1_26_0:0.3
|
||||
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
|
||||
org.apache.beam:beam-vendor-sdks-java-extensions-protobuf:2.23.0
|
||||
org.apache.commons:commons-compress:1.20
|
||||
org.apache.commons:commons-exec:1.3
|
||||
org.apache.commons:commons-lang3:3.5
|
||||
org.apache.httpcomponents:httpclient:4.5.11
|
||||
org.apache.httpcomponents:httpcore:4.4.13
|
||||
@@ -227,6 +236,7 @@ org.jboss:jandex:2.1.3.Final
|
||||
org.jetbrains:annotations:19.0.0
|
||||
org.joda:joda-money:1.0.1
|
||||
org.json:json:20160810
|
||||
org.jsoup:jsoup:1.13.1
|
||||
org.jvnet.staxex:stax-ex:1.8
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
@@ -241,6 +251,8 @@ org.rnorth.duct-tape:duct-tape:1.0.8
|
||||
org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
org.rnorth:tcp-unix-socket-proxy:1.0.2
|
||||
org.scijava:native-lib-loader:2.0.2
|
||||
org.slf4j:jcl-over-slf4j:1.7.30
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.testcontainers:database-commons:1.14.3
|
||||
org.testcontainers:jdbc:1.14.3
|
||||
@@ -249,6 +261,7 @@ org.testcontainers:testcontainers:1.14.3
|
||||
org.threeten:threetenbp:1.4.1
|
||||
org.tukaani:xz:1.8
|
||||
org.w3c.css:sac:1.3
|
||||
org.webjars.npm:viz.js-for-graphviz-java:2.1.3
|
||||
org.xerial.snappy:snappy-java:1.1.4
|
||||
org.yaml:snakeyaml:1.17
|
||||
us.fatehi:schemacrawler-api:16.10.1
|
||||
|
||||
@@ -6,6 +6,10 @@ aopalliance:aopalliance:1.0
|
||||
args4j:args4j:2.33
|
||||
cglib:cglib-nodep:2.2
|
||||
com.beust:jcommander:1.60
|
||||
com.eclipsesource.j2v8:j2v8_linux_x86_64:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_macosx_x86_64:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_win32_x86:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_win32_x86_64:4.6.0
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.10.2
|
||||
com.fasterxml.jackson.core:jackson-core:2.10.2
|
||||
com.fasterxml.jackson.core:jackson-databind:2.10.2
|
||||
@@ -130,6 +134,9 @@ com.zaxxer:HikariCP:3.2.0
|
||||
commons-codec:commons-codec:1.13
|
||||
commons-logging:commons-logging:1.2
|
||||
dnsjava:dnsjava:2.1.7
|
||||
guru.nidi.com.kitfox:svgSalamander:1.1.3
|
||||
guru.nidi:graphviz-java-all-j2v8:0.17.0
|
||||
guru.nidi:graphviz-java:0.17.0
|
||||
io.dropwizard.metrics:metrics-core:3.2.6
|
||||
io.github.classgraph:classgraph:4.8.65
|
||||
io.grpc:grpc-all:1.27.2
|
||||
@@ -176,6 +183,7 @@ javax.validation:validation-api:1.0.0.GA
|
||||
javax.xml.bind:jaxb-api:2.3.1
|
||||
jline:jline:1.0
|
||||
joda-time:joda-time:2.10.5
|
||||
net.arnx:nashorn-promise:0.1.1
|
||||
net.bytebuddy:byte-buddy:1.10.10
|
||||
net.java.dev.jna:jna-platform:5.5.0
|
||||
net.java.dev.jna:jna:5.5.0
|
||||
@@ -197,6 +205,7 @@ org.apache.beam:beam-vendor-grpc-1_26_0:0.3
|
||||
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
|
||||
org.apache.beam:beam-vendor-sdks-java-extensions-protobuf:2.23.0
|
||||
org.apache.commons:commons-compress:1.20
|
||||
org.apache.commons:commons-exec:1.3
|
||||
org.apache.commons:commons-lang3:3.5
|
||||
org.apache.httpcomponents:httpclient:4.5.11
|
||||
org.apache.httpcomponents:httpcore:4.4.13
|
||||
@@ -226,6 +235,7 @@ org.jboss:jandex:2.1.3.Final
|
||||
org.jetbrains:annotations:19.0.0
|
||||
org.joda:joda-money:1.0.1
|
||||
org.json:json:20160810
|
||||
org.jsoup:jsoup:1.13.1
|
||||
org.jvnet.staxex:stax-ex:1.8
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
@@ -240,6 +250,8 @@ org.rnorth.duct-tape:duct-tape:1.0.8
|
||||
org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
org.rnorth:tcp-unix-socket-proxy:1.0.2
|
||||
org.scijava:native-lib-loader:2.0.2
|
||||
org.slf4j:jcl-over-slf4j:1.7.30
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.slf4j:slf4j-jdk14:1.7.28
|
||||
org.testcontainers:database-commons:1.14.3
|
||||
@@ -249,6 +261,7 @@ org.testcontainers:testcontainers:1.14.3
|
||||
org.threeten:threetenbp:1.4.1
|
||||
org.tukaani:xz:1.8
|
||||
org.w3c.css:sac:1.3
|
||||
org.webjars.npm:viz.js-for-graphviz-java:2.1.3
|
||||
org.xerial.snappy:snappy-java:1.1.4
|
||||
org.yaml:snakeyaml:1.17
|
||||
us.fatehi:schemacrawler-api:16.10.1
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# 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.
|
||||
com.github.ben-manes.caffeine:caffeine:2.7.0
|
||||
com.github.kevinstern:software-and-algorithms:1.0
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.google.auto.value:auto-value:1.6.3
|
||||
com.google.auto:auto-common:0.10
|
||||
com.google.code.findbugs:jFormatString:3.0.0
|
||||
@@ -11,11 +11,11 @@ com.google.dagger:dagger-compiler:2.28
|
||||
com.google.dagger:dagger-producers:2.28
|
||||
com.google.dagger:dagger-spi:2.28
|
||||
com.google.dagger:dagger:2.28
|
||||
com.google.errorprone:error_prone_annotation:2.3.3
|
||||
com.google.errorprone:error_prone_annotation:2.3.4
|
||||
com.google.errorprone:error_prone_annotations:2.3.4
|
||||
com.google.errorprone:error_prone_check_api:2.3.3
|
||||
com.google.errorprone:error_prone_core:2.3.3
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.3
|
||||
com.google.errorprone:error_prone_check_api:2.3.4
|
||||
com.google.errorprone:error_prone_core:2.3.4
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.4
|
||||
com.google.errorprone:javac-shaded:9-dev-r4023-3
|
||||
com.google.googlejavaformat:google-java-format:1.5
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
@@ -30,11 +30,14 @@ javax.inject:javax.inject:1
|
||||
javax.persistence:javax.persistence-api:2.2
|
||||
net.ltgt.gradle.incap:incap:0.2
|
||||
org.checkerframework:checker-compat-qual:2.5.3
|
||||
org.checkerframework:checker-qual:2.11.1
|
||||
org.checkerframework:dataflow:2.5.3
|
||||
org.checkerframework:javacutil:2.5.3
|
||||
org.checkerframework:checker-qual:3.0.0
|
||||
org.checkerframework:dataflow:3.0.0
|
||||
org.checkerframework:javacutil:3.0.0
|
||||
org.jetbrains.kotlin:kotlin-stdlib-common:1.3.61
|
||||
org.jetbrains.kotlin:kotlin-stdlib:1.3.61
|
||||
org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.1.0
|
||||
org.jetbrains:annotations:13.0
|
||||
org.pcollections:pcollections:2.1.2
|
||||
org.plumelib:plume-util:1.0.6
|
||||
org.plumelib:reflection-util:0.0.2
|
||||
org.plumelib:require-javadoc:0.1.0
|
||||
|
||||
@@ -248,6 +248,7 @@ org.jboss:jandex:2.1.3.Final
|
||||
org.jetbrains:annotations:19.0.0
|
||||
org.joda:joda-money:1.0.1
|
||||
org.json:json:20160810
|
||||
org.jsoup:jsoup:1.13.1
|
||||
org.junit-pioneer:junit-pioneer:0.7.0
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.2
|
||||
|
||||
@@ -247,6 +247,7 @@ org.jboss:jandex:2.1.3.Final
|
||||
org.jetbrains:annotations:19.0.0
|
||||
org.joda:joda-money:1.0.1
|
||||
org.json:json:20160810
|
||||
org.jsoup:jsoup:1.13.1
|
||||
org.junit-pioneer:junit-pioneer:0.7.0
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.2
|
||||
|
||||
@@ -6,6 +6,10 @@ aopalliance:aopalliance:1.0
|
||||
args4j:args4j:2.33
|
||||
cglib:cglib-nodep:2.2
|
||||
com.beust:jcommander:1.60
|
||||
com.eclipsesource.j2v8:j2v8_linux_x86_64:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_macosx_x86_64:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_win32_x86:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_win32_x86_64:4.6.0
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-core:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-databind:2.11.2
|
||||
@@ -138,6 +142,9 @@ com.zaxxer:HikariCP:3.2.0
|
||||
commons-codec:commons-codec:1.13
|
||||
commons-logging:commons-logging:1.2
|
||||
dnsjava:dnsjava:2.1.7
|
||||
guru.nidi.com.kitfox:svgSalamander:1.1.3
|
||||
guru.nidi:graphviz-java-all-j2v8:0.17.0
|
||||
guru.nidi:graphviz-java:0.17.0
|
||||
io.dropwizard.metrics:metrics-core:3.2.6
|
||||
io.github.classgraph:classgraph:4.8.65
|
||||
io.github.java-diff-utils:java-diff-utils:4.0
|
||||
@@ -186,6 +193,7 @@ javax.xml.bind:jaxb-api:2.3.1
|
||||
jline:jline:1.0
|
||||
joda-time:joda-time:2.10.5
|
||||
junit:junit:4.13
|
||||
net.arnx:nashorn-promise:0.1.1
|
||||
net.bytebuddy:byte-buddy-agent:1.10.5
|
||||
net.bytebuddy:byte-buddy:1.10.10
|
||||
net.java.dev.jna:jna-platform:5.5.0
|
||||
@@ -252,6 +260,7 @@ org.jboss:jandex:2.1.3.Final
|
||||
org.jetbrains:annotations:19.0.0
|
||||
org.joda:joda-money:1.0.1
|
||||
org.json:json:20160810
|
||||
org.jsoup:jsoup:1.13.1
|
||||
org.junit-pioneer:junit-pioneer:0.7.0
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.2
|
||||
@@ -290,6 +299,8 @@ org.seleniumhq.selenium:selenium-opera-driver:3.141.59
|
||||
org.seleniumhq.selenium:selenium-remote-driver:3.141.59
|
||||
org.seleniumhq.selenium:selenium-safari-driver:3.141.59
|
||||
org.seleniumhq.selenium:selenium-support:3.141.59
|
||||
org.slf4j:jcl-over-slf4j:1.7.30
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.testcontainers:database-commons:1.14.3
|
||||
org.testcontainers:jdbc:1.14.3
|
||||
@@ -300,6 +311,7 @@ org.testcontainers:testcontainers:1.14.3
|
||||
org.threeten:threetenbp:1.4.1
|
||||
org.tukaani:xz:1.8
|
||||
org.w3c.css:sac:1.3
|
||||
org.webjars.npm:viz.js-for-graphviz-java:2.1.3
|
||||
org.xerial.snappy:snappy-java:1.1.4
|
||||
org.yaml:snakeyaml:1.17
|
||||
us.fatehi:schemacrawler-api:16.10.1
|
||||
|
||||
@@ -6,6 +6,10 @@ aopalliance:aopalliance:1.0
|
||||
args4j:args4j:2.33
|
||||
cglib:cglib-nodep:2.2
|
||||
com.beust:jcommander:1.60
|
||||
com.eclipsesource.j2v8:j2v8_linux_x86_64:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_macosx_x86_64:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_win32_x86:4.6.0
|
||||
com.eclipsesource.j2v8:j2v8_win32_x86_64:4.6.0
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-core:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-databind:2.11.2
|
||||
@@ -138,6 +142,9 @@ com.zaxxer:HikariCP:3.2.0
|
||||
commons-codec:commons-codec:1.13
|
||||
commons-logging:commons-logging:1.2
|
||||
dnsjava:dnsjava:2.1.7
|
||||
guru.nidi.com.kitfox:svgSalamander:1.1.3
|
||||
guru.nidi:graphviz-java-all-j2v8:0.17.0
|
||||
guru.nidi:graphviz-java:0.17.0
|
||||
io.dropwizard.metrics:metrics-core:3.2.6
|
||||
io.github.classgraph:classgraph:4.8.65
|
||||
io.github.java-diff-utils:java-diff-utils:4.0
|
||||
@@ -186,6 +193,7 @@ javax.xml.bind:jaxb-api:2.3.1
|
||||
jline:jline:1.0
|
||||
joda-time:joda-time:2.10.5
|
||||
junit:junit:4.13
|
||||
net.arnx:nashorn-promise:0.1.1
|
||||
net.bytebuddy:byte-buddy-agent:1.10.5
|
||||
net.bytebuddy:byte-buddy:1.10.10
|
||||
net.java.dev.jna:jna-platform:5.5.0
|
||||
@@ -252,6 +260,7 @@ org.jboss:jandex:2.1.3.Final
|
||||
org.jetbrains:annotations:19.0.0
|
||||
org.joda:joda-money:1.0.1
|
||||
org.json:json:20160810
|
||||
org.jsoup:jsoup:1.13.1
|
||||
org.junit-pioneer:junit-pioneer:0.7.0
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.2
|
||||
@@ -290,6 +299,8 @@ org.seleniumhq.selenium:selenium-opera-driver:3.141.59
|
||||
org.seleniumhq.selenium:selenium-remote-driver:3.141.59
|
||||
org.seleniumhq.selenium:selenium-safari-driver:3.141.59
|
||||
org.seleniumhq.selenium:selenium-support:3.141.59
|
||||
org.slf4j:jcl-over-slf4j:1.7.30
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.slf4j:slf4j-jdk14:1.7.28
|
||||
org.testcontainers:database-commons:1.14.3
|
||||
@@ -301,6 +312,7 @@ org.testcontainers:testcontainers:1.14.3
|
||||
org.threeten:threetenbp:1.4.1
|
||||
org.tukaani:xz:1.8
|
||||
org.w3c.css:sac:1.3
|
||||
org.webjars.npm:viz.js-for-graphviz-java:2.1.3
|
||||
org.xerial.snappy:snappy-java:1.1.4
|
||||
org.yaml:snakeyaml:1.17
|
||||
us.fatehi:schemacrawler-api:16.10.1
|
||||
|
||||
@@ -16,9 +16,12 @@ package google.registry.config;
|
||||
|
||||
import static com.google.common.base.Suppliers.memoize;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.collect.ImmutableSortedMap.toImmutableSortedMap;
|
||||
import static google.registry.config.ConfigUtils.makeUrl;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static google.registry.util.ResourceUtils.readResourceUtf8;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
import static java.util.Comparator.naturalOrder;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Ascii;
|
||||
@@ -27,6 +30,7 @@ import com.google.common.base.Strings;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import google.registry.util.TaskQueueUtils;
|
||||
@@ -46,6 +50,7 @@ import javax.inject.Qualifier;
|
||||
import javax.inject.Singleton;
|
||||
import javax.mail.internet.AddressException;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeConstants;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
@@ -1345,6 +1350,33 @@ public final class RegistryConfig {
|
||||
public static String provideRdapTosStaticUrl(RegistryConfigSettings config) {
|
||||
return config.registryPolicy.rdapTosStaticUrl;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("maxValidityDaysSchedule")
|
||||
public static ImmutableSortedMap<DateTime, Integer> provideValidityDaysMap(
|
||||
RegistryConfigSettings config) {
|
||||
return config.sslCertificateValidation.maxValidityDaysSchedule.entrySet().stream()
|
||||
.collect(
|
||||
toImmutableSortedMap(
|
||||
naturalOrder(),
|
||||
e ->
|
||||
e.getKey().equals("START_OF_TIME")
|
||||
? START_OF_TIME
|
||||
: DateTime.parse(e.getKey()),
|
||||
e -> e.getValue()));
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("expirationWarningDays")
|
||||
public static int provideDaysToExpiration(RegistryConfigSettings config) {
|
||||
return config.sslCertificateValidation.expirationWarningDays;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("minimumRsaKeyLength")
|
||||
public static int provideMinimumRsaKeyLength(RegistryConfigSettings config) {
|
||||
return config.sslCertificateValidation.minimumRsaKeyLength;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the App Engine project ID, which is based off the environment name. */
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package google.registry.config;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/** The POJO that YAML config files are deserialized into. */
|
||||
public class RegistryConfigSettings {
|
||||
@@ -38,6 +39,7 @@ public class RegistryConfigSettings {
|
||||
public Beam beam;
|
||||
public Keyring keyring;
|
||||
public RegistryTool registryTool;
|
||||
public SslCertificateValidation sslCertificateValidation;
|
||||
|
||||
/** Configuration options that apply to the entire App Engine project. */
|
||||
public static class AppEngine {
|
||||
@@ -218,4 +220,11 @@ public class RegistryConfigSettings {
|
||||
public String clientSecret;
|
||||
public String username;
|
||||
}
|
||||
|
||||
/** Configuration for the certificate checker. */
|
||||
public static class SslCertificateValidation {
|
||||
public Map<String, Integer> maxValidityDaysSchedule;
|
||||
public int expirationWarningDays;
|
||||
public int minimumRsaKeyLength;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,3 +446,17 @@ registryTool:
|
||||
# OAuth client secret used by the tool.
|
||||
clientSecret: YOUR_CLIENT_SECRET
|
||||
username: toolusername
|
||||
|
||||
# Configuration options for checking SSL certificates.
|
||||
sslCertificateValidation:
|
||||
# A map specifying the maximum amount of days the certificate can be valid.
|
||||
# The entry key is the date closest before the date the certificate was issued
|
||||
# and the entry value is the applicable maximum validity days for that certificate.
|
||||
maxValidityDaysSchedule:
|
||||
"START_OF_TIME": 825
|
||||
"2020-09-01T00:00:00Z": 398
|
||||
# The number of days before a certificate expires that indicates the
|
||||
# certificate is nearing expiration and warnings should be sent.
|
||||
expirationWarningDays: 30
|
||||
# The minimum number of bits an RSA key must contain
|
||||
minimumRsaKeyLength: 2048
|
||||
|
||||
@@ -12,17 +12,26 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.util;
|
||||
package google.registry.flows.certs;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.DateTimeUtils;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.util.Date;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Days;
|
||||
|
||||
@@ -53,11 +62,12 @@ public class CertificateChecker {
|
||||
* );
|
||||
* </pre>
|
||||
*/
|
||||
// TODO(sarahbot): Inject this.
|
||||
@Inject
|
||||
public CertificateChecker(
|
||||
ImmutableSortedMap<DateTime, Integer> maxValidityLengthSchedule,
|
||||
int daysToExpiration,
|
||||
int minimumRsaKeyLength,
|
||||
@Config("maxValidityDaysSchedule")
|
||||
ImmutableSortedMap<DateTime, Integer> maxValidityLengthSchedule,
|
||||
@Config("expirationWarningDays") int daysToExpiration,
|
||||
@Config("minimumRsaKeyLength") int minimumRsaKeyLength,
|
||||
Clock clock) {
|
||||
checkArgument(
|
||||
maxValidityLengthSchedule.containsKey(START_OF_TIME),
|
||||
@@ -69,8 +79,23 @@ public class CertificateChecker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a certificate for violations and returns a list of all the violations the certificate
|
||||
* has.
|
||||
* Checks the given certificate string for violations and throws an exception if any violations
|
||||
* exist.
|
||||
*/
|
||||
public void validateCertificate(String certificateString) {
|
||||
ImmutableSet<CertificateViolation> violations = checkCertificate(certificateString);
|
||||
if (!violations.isEmpty()) {
|
||||
String displayMessages =
|
||||
violations.stream()
|
||||
.map(violation -> getViolationDisplayMessage(violation))
|
||||
.collect(Collectors.joining("\n"));
|
||||
throw new IllegalArgumentException(displayMessages);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a given certificate for violations and returns a list of all the violations the
|
||||
* certificate has.
|
||||
*/
|
||||
public ImmutableSet<CertificateViolation> checkCertificate(X509Certificate certificate) {
|
||||
ImmutableSet.Builder<CertificateViolation> violations = new ImmutableSet.Builder<>();
|
||||
@@ -105,6 +130,25 @@ public class CertificateChecker {
|
||||
return violations.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a given string to a certificate and checks it for violations, returning a list of all
|
||||
* the violations the certificate has.
|
||||
*/
|
||||
public ImmutableSet<CertificateViolation> checkCertificate(String certificateString) {
|
||||
X509Certificate certificate;
|
||||
|
||||
try {
|
||||
certificate =
|
||||
(X509Certificate)
|
||||
CertificateFactory.getInstance("X509")
|
||||
.generateCertificate(new ByteArrayInputStream(certificateString.getBytes(UTF_8)));
|
||||
} catch (CertificateException e) {
|
||||
throw new IllegalArgumentException("Unable to read given certificate.");
|
||||
}
|
||||
|
||||
return checkCertificate(certificate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the certificate is nearing expiration.
|
||||
*
|
||||
@@ -24,7 +24,6 @@ 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 java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
@@ -387,7 +386,7 @@ public abstract class EppResource extends BackupGroupRoot implements Buildable {
|
||||
private static LoadingCache<VKey<? extends EppResource>, EppResource> createEppResourcesCache(
|
||||
Duration expiry) {
|
||||
return CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(expiry.getMillis(), MILLISECONDS)
|
||||
.expireAfterWrite(java.time.Duration.ofMillis(expiry.getMillis()))
|
||||
.maximumSize(getEppResourceMaxCachedEntries())
|
||||
.build(CACHE_LOADER);
|
||||
}
|
||||
|
||||
@@ -61,7 +61,17 @@ public abstract class ImmutableObject implements Cloneable {
|
||||
private boolean equalsImmutableObject(ImmutableObject other) {
|
||||
return getClass().equals(other.getClass())
|
||||
&& hashCode() == other.hashCode()
|
||||
&& ModelUtils.getFieldValues(this).equals(ModelUtils.getFieldValues(other));
|
||||
&& getSignificantFields().equals(other.getSignificantFields());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the map of significant fields (fields that we care about for purposes of comparison and
|
||||
* display).
|
||||
*
|
||||
* <p>Isolated into a method so that derived classes can override it.
|
||||
*/
|
||||
protected Map<Field, Object> getSignificantFields() {
|
||||
return ModelUtils.getFieldValues(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,7 +82,7 @@ public abstract class ImmutableObject implements Cloneable {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
if (hashCode == null) {
|
||||
hashCode = Arrays.hashCode(ModelUtils.getFieldValues(this).values().toArray());
|
||||
hashCode = Arrays.hashCode(getSignificantFields().values().toArray());
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
@@ -111,7 +121,7 @@ public abstract class ImmutableObject implements Cloneable {
|
||||
@Override
|
||||
public String toString() {
|
||||
NavigableMap<String, Object> sortedFields = new TreeMap<>();
|
||||
for (Entry<Field, Object> entry : ModelUtils.getFieldValues(this).entrySet()) {
|
||||
for (Entry<Field, Object> entry : getSignificantFields().entrySet()) {
|
||||
sortedFields.put(entry.getKey().getName(), entry.getValue());
|
||||
}
|
||||
return toStringHelper(sortedFields);
|
||||
@@ -121,7 +131,7 @@ public abstract class ImmutableObject implements Cloneable {
|
||||
public String toHydratedString() {
|
||||
// We can't use ImmutableSortedMap because we need to allow null values.
|
||||
NavigableMap<String, Object> sortedFields = new TreeMap<>();
|
||||
for (Entry<Field, Object> entry : ModelUtils.getFieldValues(this).entrySet()) {
|
||||
for (Entry<Field, Object> entry : getSignificantFields().entrySet()) {
|
||||
Field field = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
sortedFields.put(
|
||||
@@ -161,7 +171,7 @@ public abstract class ImmutableObject implements Cloneable {
|
||||
// LinkedHashMap to preserve field ordering and because ImmutableMap forbids null
|
||||
// values.
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
for (Entry<Field, Object> entry : ModelUtils.getFieldValues(o).entrySet()) {
|
||||
for (Entry<Field, Object> entry : ((ImmutableObject) o).getSignificantFields().entrySet()) {
|
||||
Field field = entry.getKey();
|
||||
if (!field.isAnnotationPresent(IgnoredInDiffableMap.class)) {
|
||||
result.put(field.getName(), toMapRecursive(entry.getValue()));
|
||||
|
||||
@@ -194,7 +194,7 @@ public class ModelUtils {
|
||||
* returned map in its implementation of {@link ImmutableObject#toString} and {@link
|
||||
* ImmutableObject#equals}, which work by comparing and printing these maps.
|
||||
*/
|
||||
static Map<Field, Object> getFieldValues(Object instance) {
|
||||
public static Map<Field, Object> getFieldValues(Object instance) {
|
||||
// Don't make this ImmutableMap because field values can be null.
|
||||
Map<Field, Object> values = new LinkedHashMap<>();
|
||||
for (Field field : getAllFields(instance.getClass()).values()) {
|
||||
|
||||
@@ -59,25 +59,11 @@ public class OteStats {
|
||||
|
||||
private OteStats() {}
|
||||
|
||||
private static final Predicate<EppInput> HAS_CLAIMS_NOTICE =
|
||||
eppInput -> {
|
||||
Optional<LaunchCreateExtension> launchCreate =
|
||||
eppInput.getSingleExtension(LaunchCreateExtension.class);
|
||||
return launchCreate.isPresent() && launchCreate.get().getNotice() != null;
|
||||
};
|
||||
|
||||
private static final Predicate<EppInput> HAS_SEC_DNS =
|
||||
eppInput ->
|
||||
eppInput.getSingleExtension(SecDnsCreateExtension.class).isPresent()
|
||||
|| eppInput.getSingleExtension(SecDnsUpdateExtension.class).isPresent();
|
||||
|
||||
private static final Predicate<EppInput> IS_SUNRISE =
|
||||
eppInput -> {
|
||||
Optional<LaunchCreateExtension> launchCreate =
|
||||
eppInput.getSingleExtension(LaunchCreateExtension.class);
|
||||
return launchCreate.isPresent() && !isNullOrEmpty(launchCreate.get().getSignedMarks());
|
||||
};
|
||||
|
||||
private static final Predicate<EppInput> IS_IDN =
|
||||
eppInput ->
|
||||
((DomainCommand.Create)
|
||||
@@ -94,6 +80,18 @@ public class OteStats {
|
||||
.getResourceCommand())
|
||||
.getInetAddresses());
|
||||
|
||||
private static boolean hasClaimsNotice(EppInput eppInput) {
|
||||
Optional<LaunchCreateExtension> launchCreate =
|
||||
eppInput.getSingleExtension(LaunchCreateExtension.class);
|
||||
return launchCreate.isPresent() && launchCreate.get().getNotice() != null;
|
||||
}
|
||||
|
||||
private static boolean isSunrise(EppInput eppInput) {
|
||||
Optional<LaunchCreateExtension> launchCreate =
|
||||
eppInput.getSingleExtension(LaunchCreateExtension.class);
|
||||
return launchCreate.isPresent() && !isNullOrEmpty(launchCreate.get().getSignedMarks());
|
||||
}
|
||||
|
||||
/** Enum defining the distinct statistics (types of registrar actions) to record. */
|
||||
public enum StatType {
|
||||
CONTACT_CREATES(0, equalTo(Type.CONTACT_CREATE)),
|
||||
@@ -107,8 +105,8 @@ public class OteStats {
|
||||
DOMAIN_CREATES(0, equalTo(Type.DOMAIN_CREATE)),
|
||||
DOMAIN_CREATES_ASCII(1, equalTo(Type.DOMAIN_CREATE), IS_IDN.negate()),
|
||||
DOMAIN_CREATES_IDN(1, equalTo(Type.DOMAIN_CREATE), IS_IDN),
|
||||
DOMAIN_CREATES_START_DATE_SUNRISE(1, equalTo(Type.DOMAIN_CREATE), IS_SUNRISE),
|
||||
DOMAIN_CREATES_WITH_CLAIMS_NOTICE(1, equalTo(Type.DOMAIN_CREATE), HAS_CLAIMS_NOTICE),
|
||||
DOMAIN_CREATES_START_DATE_SUNRISE(1, equalTo(Type.DOMAIN_CREATE), OteStats::isSunrise),
|
||||
DOMAIN_CREATES_WITH_CLAIMS_NOTICE(1, equalTo(Type.DOMAIN_CREATE), OteStats::hasClaimsNotice),
|
||||
DOMAIN_CREATES_WITH_FEE(
|
||||
1,
|
||||
equalTo(Type.DOMAIN_CREATE),
|
||||
|
||||
@@ -60,7 +60,9 @@ public class ContactHistory extends HistoryEntry implements SqlEntity {
|
||||
@Id
|
||||
@Access(AccessType.PROPERTY)
|
||||
public String getContactRepoId() {
|
||||
return parent.getName();
|
||||
// We need to handle null case here because Hibernate sometimes accesses this method before
|
||||
// parent gets initialized
|
||||
return parent == null ? null : parent.getName();
|
||||
}
|
||||
|
||||
/** This method is private because it is only used by Hibernate. */
|
||||
|
||||
@@ -303,14 +303,13 @@ public class DomainContent extends EppResource
|
||||
allContacts.stream().map(DesignatedContact::reconstitute).collect(toImmutableSet());
|
||||
setContactFields(allContacts, true);
|
||||
|
||||
// We have to return the cloned object here because the original object's
|
||||
// hashcode is not correct due to the change to its domainRepoId. The cloned
|
||||
// object will have a null hashcode so that it can get a recalculated hashcode
|
||||
// when its hashCode() is invoked.
|
||||
// We have to return the cloned object here because the original object's hashcode is not
|
||||
// correct due to the change to its domainRepoId and history ids. The cloned object will have a
|
||||
// null hashcode so that it can get a recalculated hashcode when its hashCode() is invoked.
|
||||
// TODO(b/162739503): Remove this after fully migrating to Cloud SQL.
|
||||
gracePeriods =
|
||||
nullToEmptyImmutableCopy(gracePeriods).stream()
|
||||
.map(gracePeriod -> gracePeriod.cloneWithDomainRepoId(getRepoId()))
|
||||
.map(gracePeriod -> gracePeriod.cloneAfterOfyLoad(getRepoId()))
|
||||
.collect(toImmutableSet());
|
||||
|
||||
// Restore history record ids.
|
||||
@@ -352,9 +351,13 @@ public class DomainContent extends EppResource
|
||||
restoreOfyFrom(myKey, autorenewBillingEvent, autorenewBillingEventHistoryId);
|
||||
autorenewPollMessage =
|
||||
restoreOfyFrom(myKey, autorenewPollMessage, autorenewPollMessageHistoryId);
|
||||
|
||||
if (transferData != null) {
|
||||
transferData.restoreOfyKeys(myKey);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> VKey<T> restoreOfyFrom(Key<DomainBase> domainKey, VKey<T> key, Long historyId) {
|
||||
public static <T> VKey<T> restoreOfyFrom(Key<DomainBase> domainKey, VKey<T> key, Long historyId) {
|
||||
if (historyId == null) {
|
||||
// This is a legacy key (or a null key, in which case this works too)
|
||||
return VKey.restoreOfyFrom(key, EntityGroupRoot.class, "per-tld");
|
||||
@@ -716,7 +719,14 @@ public class DomainContent extends EppResource
|
||||
+ " use DomainBase instead");
|
||||
}
|
||||
|
||||
private static Long getHistoryId(VKey<?> key) {
|
||||
/**
|
||||
* Obtains a history id from the given key.
|
||||
*
|
||||
* <p>The key must be a composite key either of the form domain-key/history-key/long-event-key or
|
||||
* EntityGroupRoot/long-event-key (for legacy keys). In the latter case or for a null key returns
|
||||
* a history id of null.
|
||||
*/
|
||||
public static Long getHistoryId(VKey<?> key) {
|
||||
if (key == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -14,14 +14,17 @@
|
||||
|
||||
package google.registry.model.domain;
|
||||
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.EntitySubclass;
|
||||
import com.googlecode.objectify.annotation.Ignore;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.domain.DomainHistory.DomainHistoryId;
|
||||
import google.registry.model.domain.secdns.DomainDsDataHistory;
|
||||
import google.registry.model.host.HostResource;
|
||||
import google.registry.model.reporting.DomainTransactionRecord;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
@@ -40,10 +43,12 @@ import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.IdClass;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinColumns;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.PostLoad;
|
||||
@@ -75,7 +80,9 @@ public class DomainHistory extends HistoryEntry implements SqlEntity {
|
||||
@Id
|
||||
@Access(AccessType.PROPERTY)
|
||||
public String getDomainRepoId() {
|
||||
return parent.getName();
|
||||
// We need to handle null case here because Hibernate sometimes accesses this method before
|
||||
// parent gets initialized
|
||||
return parent == null ? null : parent.getName();
|
||||
}
|
||||
|
||||
/** This method is private because it is only used by Hibernate. */
|
||||
@@ -93,6 +100,24 @@ public class DomainHistory extends HistoryEntry implements SqlEntity {
|
||||
@Column(name = "host_repo_id")
|
||||
Set<VKey<HostResource>> nsHosts;
|
||||
|
||||
@OneToMany(
|
||||
cascade = {CascadeType.ALL},
|
||||
fetch = FetchType.EAGER,
|
||||
orphanRemoval = true)
|
||||
@JoinColumns({
|
||||
@JoinColumn(
|
||||
name = "domainHistoryRevisionId",
|
||||
referencedColumnName = "historyRevisionId",
|
||||
insertable = false,
|
||||
updatable = false),
|
||||
@JoinColumn(
|
||||
name = "domainRepoId",
|
||||
referencedColumnName = "domainRepoId",
|
||||
insertable = false,
|
||||
updatable = false)
|
||||
})
|
||||
Set<DomainDsDataHistory> dsDataHistories;
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
@Access(AccessType.PROPERTY)
|
||||
@@ -127,14 +152,24 @@ public class DomainHistory extends HistoryEntry implements SqlEntity {
|
||||
*
|
||||
* <p>This will be empty for any DomainHistory/HistoryEntry generated before this field was added,
|
||||
* mid-2017, as well as any action that does not generate billable events (e.g. updates).
|
||||
*
|
||||
* <p>This method is dedicated for Hibernate, external caller should use {@link
|
||||
* #getDomainTransactionRecords()}.
|
||||
*/
|
||||
@Access(AccessType.PROPERTY)
|
||||
@OneToMany(cascade = {CascadeType.ALL})
|
||||
@JoinColumn(name = "historyRevisionId", referencedColumnName = "historyRevisionId")
|
||||
@JoinColumn(name = "domainRepoId", referencedColumnName = "domainRepoId")
|
||||
@Override
|
||||
public Set<DomainTransactionRecord> getDomainTransactionRecords() {
|
||||
return super.getDomainTransactionRecords();
|
||||
@SuppressWarnings("unused")
|
||||
private Set<DomainTransactionRecord> getInternalDomainTransactionRecords() {
|
||||
return domainTransactionRecords;
|
||||
}
|
||||
|
||||
/** Sets the domain transaction records. This method is dedicated for Hibernate. */
|
||||
@SuppressWarnings("unused")
|
||||
private void setInternalDomainTransactionRecords(
|
||||
Set<DomainTransactionRecord> domainTransactionRecords) {
|
||||
this.domainTransactionRecords = domainTransactionRecords;
|
||||
}
|
||||
|
||||
@Id
|
||||
@@ -150,6 +185,11 @@ public class DomainHistory extends HistoryEntry implements SqlEntity {
|
||||
return nsHosts;
|
||||
}
|
||||
|
||||
/** Returns the collection of {@link DomainDsDataHistory} instances. */
|
||||
public ImmutableSet<DomainDsDataHistory> getDsDataHistories() {
|
||||
return nullToEmptyImmutableCopy(dsDataHistories);
|
||||
}
|
||||
|
||||
/**
|
||||
* The values of all the fields on the {@link DomainContent} object after the action represented
|
||||
* by this history object was executed.
|
||||
@@ -266,9 +306,6 @@ public class DomainHistory extends HistoryEntry implements SqlEntity {
|
||||
|
||||
public Builder setDomainContent(DomainContent domainContent) {
|
||||
getInstance().domainContent = domainContent;
|
||||
if (domainContent != null) {
|
||||
getInstance().nsHosts = nullToEmptyImmutableCopy(domainContent.nsHosts);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -276,5 +313,22 @@ public class DomainHistory extends HistoryEntry implements SqlEntity {
|
||||
getInstance().parent = Key.create(DomainBase.class, domainRepoId);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainHistory build() {
|
||||
DomainHistory instance = super.build();
|
||||
// TODO(b/171990736): Assert instance.domainContent is not null after database migration.
|
||||
// Note that we cannot assert that instance.domainContent is not null here because this
|
||||
// builder is also used to convert legacy HistoryEntry objects to DomainHistory, when
|
||||
// domainContent is not available.
|
||||
if (instance.domainContent != null) {
|
||||
instance.nsHosts = nullToEmptyImmutableCopy(instance.domainContent.nsHosts);
|
||||
instance.dsDataHistories =
|
||||
nullToEmptyImmutableCopy(instance.domainContent.getDsData()).stream()
|
||||
.map(dsData -> DomainDsDataHistory.createFrom(instance.id, dsData))
|
||||
.collect(toImmutableSet());
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.googlecode.objectify.annotation.Embed;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingEvent.Recurring;
|
||||
import google.registry.model.domain.rgp.GracePeriodStatus;
|
||||
import google.registry.model.ofy.ObjectifyService;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.schema.replay.DatastoreAndSqlEntity;
|
||||
import javax.annotation.Nullable;
|
||||
@@ -53,12 +54,15 @@ public class GracePeriod extends GracePeriodBase implements DatastoreAndSqlEntit
|
||||
(billingEventRecurring != null) == GracePeriodStatus.AUTO_RENEW.equals(type),
|
||||
"Recurring billing events must be present on (and only on) autorenew grace periods");
|
||||
GracePeriod instance = new GracePeriod();
|
||||
instance.id = ObjectifyService.allocateId();
|
||||
instance.type = checkArgumentNotNull(type);
|
||||
instance.domainRepoId = checkArgumentNotNull(domainRepoId);
|
||||
instance.expirationTime = checkArgumentNotNull(expirationTime);
|
||||
instance.clientId = checkArgumentNotNull(clientId);
|
||||
instance.billingEventOneTime = billingEventOneTime;
|
||||
instance.billingEventOneTimeHistoryId = DomainBase.getHistoryId(billingEventOneTime);
|
||||
instance.billingEventRecurring = billingEventRecurring;
|
||||
instance.billingEventRecurringHistoryId = DomainBase.getHistoryId(billingEventRecurring);
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -108,14 +112,16 @@ public class GracePeriod extends GracePeriodBase implements DatastoreAndSqlEntit
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a clone of this {@link GracePeriod} with {@link #domainRepoId} set to the given value.
|
||||
* Returns a clone of this {@link GracePeriod} with {@link #domainRepoId} set to the given value
|
||||
* and reconstructed history ids.
|
||||
*
|
||||
* <p>TODO(b/162739503): Remove this function after fully migrating to Cloud SQL.
|
||||
*/
|
||||
public GracePeriod cloneWithDomainRepoId(String domainRepoId) {
|
||||
public GracePeriod cloneAfterOfyLoad(String domainRepoId) {
|
||||
GracePeriod clone = clone(this);
|
||||
clone.id = ObjectifyService.allocateId();
|
||||
clone.domainRepoId = checkArgumentNotNull(domainRepoId);
|
||||
clone.restoreHistoryIds();
|
||||
return clone;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,18 +14,21 @@
|
||||
|
||||
package google.registry.model.domain;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.Embed;
|
||||
import com.googlecode.objectify.annotation.Ignore;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.ModelUtils;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingEvent.OneTime;
|
||||
import google.registry.model.domain.rgp.GracePeriodStatus;
|
||||
import google.registry.persistence.VKey;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
@@ -36,7 +39,6 @@ public class GracePeriodBase extends ImmutableObject {
|
||||
|
||||
/** Unique id required for hibernate representation. */
|
||||
@javax.persistence.Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Ignore
|
||||
Long id;
|
||||
|
||||
@@ -67,6 +69,10 @@ public class GracePeriodBase extends ImmutableObject {
|
||||
@Column(name = "billing_event_id")
|
||||
VKey<OneTime> billingEventOneTime = null;
|
||||
|
||||
@Ignore
|
||||
@Column(name = "billing_event_history_id")
|
||||
Long billingEventOneTimeHistoryId;
|
||||
|
||||
/**
|
||||
* The recurring billing event corresponding to the action that triggered this grace period, if
|
||||
* applicable - i.e. if the action was an autorenew - or null in all other cases.
|
||||
@@ -75,6 +81,14 @@ public class GracePeriodBase extends ImmutableObject {
|
||||
@Column(name = "billing_recurrence_id")
|
||||
VKey<BillingEvent.Recurring> billingEventRecurring = null;
|
||||
|
||||
@Ignore
|
||||
@Column(name = "billing_recurrence_history_id")
|
||||
Long billingEventRecurringHistoryId;
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public GracePeriodStatus getType() {
|
||||
return type;
|
||||
}
|
||||
@@ -101,6 +115,7 @@ public class GracePeriodBase extends ImmutableObject {
|
||||
* period is not AUTO_RENEW.
|
||||
*/
|
||||
public VKey<BillingEvent.OneTime> getOneTimeBillingEvent() {
|
||||
restoreOfyKeys();
|
||||
return billingEventOneTime;
|
||||
}
|
||||
|
||||
@@ -109,6 +124,63 @@ public class GracePeriodBase extends ImmutableObject {
|
||||
* period is AUTO_RENEW.
|
||||
*/
|
||||
public VKey<BillingEvent.Recurring> getRecurringBillingEvent() {
|
||||
restoreOfyKeys();
|
||||
return billingEventRecurring;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores history ids for composite VKeys after a load from datastore.
|
||||
*
|
||||
* <p>For use by DomainContent.load() ONLY.
|
||||
*/
|
||||
protected void restoreHistoryIds() {
|
||||
billingEventOneTimeHistoryId = DomainBase.getHistoryId(billingEventOneTime);
|
||||
billingEventRecurringHistoryId = DomainBase.getHistoryId(billingEventRecurring);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override {@link ImmutableObject#getSignificantFields()} to exclude "id", which breaks equality
|
||||
* testing in the unit tests.
|
||||
*/
|
||||
@Override
|
||||
protected Map<Field, Object> getSignificantFields() {
|
||||
restoreOfyKeys();
|
||||
// Can't use streams or ImmutableMap because we can have null values.
|
||||
Map<Field, Object> result = new LinkedHashMap();
|
||||
for (Map.Entry<Field, Object> entry : ModelUtils.getFieldValues(this).entrySet()) {
|
||||
if (!entry.getKey().getName().equals("id")) {
|
||||
result.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores Ofy keys in the billing events.
|
||||
*
|
||||
* <p>This must be called by all methods that access the one time or recurring billing event keys.
|
||||
* When the billing event keys are loaded from SQL, they are loaded as asymmetric keys because the
|
||||
* database columns that we load them from do not contain all of the information necessary to
|
||||
* reconsitute the Ofy side of the key. In other cases, we restore the Ofy key during the
|
||||
* hibernate {@link javax.persistence.PostLoad} method from the other fields of the object, but we
|
||||
* have been unable to make this work with hibernate's internal persistence model in this case
|
||||
* because the {@link GracePeriod}'s hash code is evaluated prior to these calls, and would be
|
||||
* invalidated by changing the fields.
|
||||
*/
|
||||
private final synchronized void restoreOfyKeys() {
|
||||
if (billingEventOneTime != null && !billingEventOneTime.maybeGetOfyKey().isPresent()) {
|
||||
billingEventOneTime =
|
||||
DomainBase.restoreOfyFrom(
|
||||
Key.create(DomainBase.class, domainRepoId),
|
||||
billingEventOneTime,
|
||||
billingEventOneTimeHistoryId);
|
||||
}
|
||||
if (billingEventRecurring != null && !billingEventRecurring.maybeGetOfyKey().isPresent()) {
|
||||
billingEventRecurring =
|
||||
DomainBase.restoreOfyFrom(
|
||||
Key.create(DomainBase.class, domainRepoId),
|
||||
billingEventRecurring,
|
||||
billingEventRecurringHistoryId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,89 +17,68 @@ package google.registry.model.domain.secdns;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
import com.googlecode.objectify.annotation.Embed;
|
||||
import com.googlecode.objectify.annotation.Ignore;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.domain.secdns.DelegationSignerData.DelegationSignerDataId;
|
||||
import google.registry.schema.replay.DatastoreAndSqlEntity;
|
||||
import google.registry.model.domain.secdns.DelegationSignerData.DomainDsDataId;
|
||||
import java.io.Serializable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Access;
|
||||
import javax.persistence.AccessType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.IdClass;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.Table;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
/**
|
||||
* Holds the data necessary to construct a single Delegation Signer (DS) record for a domain.
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/rfc5910">RFC 5910</a>
|
||||
* @see <a href="http://tools.ietf.org/html/rfc4034">RFC 4034</a>
|
||||
* <p>TODO(shicong): Rename this class to DomainDsData.
|
||||
*/
|
||||
@Embed
|
||||
@XmlType(name = "dsData")
|
||||
@Entity
|
||||
@IdClass(DomainDsDataId.class)
|
||||
@Table(indexes = @Index(columnList = "domainRepoId"))
|
||||
@IdClass(DelegationSignerDataId.class)
|
||||
public class DelegationSignerData extends ImmutableObject implements DatastoreAndSqlEntity {
|
||||
public class DelegationSignerData extends DomainDsDataBase {
|
||||
|
||||
private DelegationSignerData() {}
|
||||
|
||||
@Ignore @XmlTransient @javax.persistence.Id String domainRepoId;
|
||||
|
||||
/** The identifier for this particular key in the domain. */
|
||||
@javax.persistence.Id
|
||||
@Column(nullable = false)
|
||||
int keyTag;
|
||||
|
||||
/**
|
||||
* The algorithm used by this key.
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/rfc4034#appendix-A.1">RFC 4034 Appendix A.1</a>
|
||||
*/
|
||||
@Column(nullable = false)
|
||||
@XmlElement(name = "alg")
|
||||
int algorithm;
|
||||
|
||||
/**
|
||||
* The algorithm used to generate the digest.
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/rfc4034#appendix-A.2">RFC 4034 Appendix A.2</a>
|
||||
*/
|
||||
@Column(nullable = false)
|
||||
int digestType;
|
||||
|
||||
/**
|
||||
* The hexBinary digest of the public key.
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/rfc4034#section-5.1.4">RFC 4034 Section 5.1.4</a>
|
||||
*/
|
||||
@Column(nullable = false)
|
||||
@XmlJavaTypeAdapter(HexBinaryAdapter.class)
|
||||
byte[] digest;
|
||||
@Override
|
||||
@Id
|
||||
@Access(AccessType.PROPERTY)
|
||||
public String getDomainRepoId() {
|
||||
return super.getDomainRepoId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Id
|
||||
@Access(AccessType.PROPERTY)
|
||||
public int getKeyTag() {
|
||||
return keyTag;
|
||||
return super.getKeyTag();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Id
|
||||
@Access(AccessType.PROPERTY)
|
||||
public int getAlgorithm() {
|
||||
return algorithm;
|
||||
return super.getAlgorithm();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Id
|
||||
@Access(AccessType.PROPERTY)
|
||||
public int getDigestType() {
|
||||
return digestType;
|
||||
return super.getDigestType();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Id
|
||||
@Access(AccessType.PROPERTY)
|
||||
public byte[] getDigest() {
|
||||
return digest;
|
||||
}
|
||||
|
||||
public String getDigestAsString() {
|
||||
return digest == null ? "" : DatatypeConverter.printHexBinary(digest);
|
||||
return super.getDigest();
|
||||
}
|
||||
|
||||
public DelegationSignerData cloneWithDomainRepoId(String domainRepoId) {
|
||||
@@ -135,30 +114,135 @@ public class DelegationSignerData extends ImmutableObject implements DatastoreAn
|
||||
return create(keyTag, algorithm, digestType, DatatypeConverter.parseHexBinary(digestAsHex));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the presentation format of this DS record.
|
||||
*
|
||||
* @see <a href="https://tools.ietf.org/html/rfc4034#section-5.3">RFC 4034 Section 5.3</a>
|
||||
*/
|
||||
public String toRrData() {
|
||||
return String.format(
|
||||
"%d %d %d %s",
|
||||
this.keyTag, this.algorithm, this.digestType, DatatypeConverter.printHexBinary(digest));
|
||||
}
|
||||
/** Class to represent the composite primary key of {@link DelegationSignerData} entity. */
|
||||
static class DomainDsDataId extends ImmutableObject implements Serializable {
|
||||
|
||||
static class DelegationSignerDataId extends ImmutableObject implements Serializable {
|
||||
String domainRepoId;
|
||||
|
||||
int keyTag;
|
||||
|
||||
private DelegationSignerDataId() {}
|
||||
int algorithm;
|
||||
|
||||
private DelegationSignerDataId(String domainRepoId, int keyTag) {
|
||||
int digestType;
|
||||
|
||||
byte[] digest;
|
||||
|
||||
/** Hibernate requires this default constructor. */
|
||||
private DomainDsDataId() {}
|
||||
|
||||
/** Constructs a {link DomainDsDataId} instance. */
|
||||
DomainDsDataId(String domainRepoId, int keyTag, int algorithm, int digestType, byte[] digest) {
|
||||
this.domainRepoId = domainRepoId;
|
||||
this.keyTag = keyTag;
|
||||
this.algorithm = algorithm;
|
||||
this.digestType = digestType;
|
||||
this.digest = digest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the domain repository ID.
|
||||
*
|
||||
* <p>This method is private because it is only used by Hibernate.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private String getDomainRepoId() {
|
||||
return domainRepoId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key tag.
|
||||
*
|
||||
* <p>This method is private because it is only used by Hibernate.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private int getKeyTag() {
|
||||
return keyTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the algorithm.
|
||||
*
|
||||
* <p>This method is private because it is only used by Hibernate.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private int getAlgorithm() {
|
||||
return algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the digest type.
|
||||
*
|
||||
* <p>This method is private because it is only used by Hibernate.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private int getDigestType() {
|
||||
return digestType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the digest.
|
||||
*
|
||||
* <p>This method is private because it is only used by Hibernate.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private byte[] getDigest() {
|
||||
return digest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the domain repository ID.
|
||||
*
|
||||
* <p>This method is private because it is only used by Hibernate.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private void setDomainRepoId(String domainRepoId) {
|
||||
this.domainRepoId = domainRepoId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key tag.
|
||||
*
|
||||
* <p>This method is private because it is only used by Hibernate.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private void setKeyTag(int keyTag) {
|
||||
this.keyTag = keyTag;
|
||||
}
|
||||
|
||||
public static DelegationSignerDataId create(String domainRepoId, int keyTag) {
|
||||
return new DelegationSignerDataId(checkArgumentNotNull(domainRepoId), keyTag);
|
||||
/**
|
||||
* Sets the algorithm.
|
||||
*
|
||||
* <p>This method is private because it is only used by Hibernate.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private void setAlgorithm(int algorithm) {
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the digest type.
|
||||
*
|
||||
* <p>This method is private because it is only used by Hibernate.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private void setDigestType(int digestType) {
|
||||
this.digestType = digestType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the digest.
|
||||
*
|
||||
* <p>This method is private because it is only used by Hibernate.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private void setDigest(byte[] digest) {
|
||||
this.digest = digest;
|
||||
}
|
||||
|
||||
public static DomainDsDataId create(
|
||||
String domainRepoId, int keyTag, int algorithm, int digestType, byte[] digest) {
|
||||
return new DomainDsDataId(
|
||||
domainRepoId, keyTag, algorithm, digestType, checkArgumentNotNull(digest));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
// Copyright 2020 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.model.domain.secdns;
|
||||
|
||||
import com.googlecode.objectify.annotation.Embed;
|
||||
import com.googlecode.objectify.annotation.Ignore;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.schema.replay.DatastoreAndSqlEntity;
|
||||
import javax.persistence.Access;
|
||||
import javax.persistence.AccessType;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.Transient;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
/** Base class for {@link DelegationSignerData} and {@link DomainDsDataHistory}. */
|
||||
@Embed
|
||||
@MappedSuperclass
|
||||
@Access(AccessType.FIELD)
|
||||
public abstract class DomainDsDataBase extends ImmutableObject implements DatastoreAndSqlEntity {
|
||||
|
||||
@Ignore @XmlTransient @Transient String domainRepoId;
|
||||
|
||||
/** The identifier for this particular key in the domain. */
|
||||
@Transient int keyTag;
|
||||
|
||||
/**
|
||||
* The algorithm used by this key.
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/rfc4034#appendix-A.1">RFC 4034 Appendix A.1</a>
|
||||
*/
|
||||
@Transient
|
||||
@XmlElement(name = "alg")
|
||||
int algorithm;
|
||||
|
||||
/**
|
||||
* The algorithm used to generate the digest.
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/rfc4034#appendix-A.2">RFC 4034 Appendix A.2</a>
|
||||
*/
|
||||
@Transient int digestType;
|
||||
|
||||
/**
|
||||
* The hexBinary digest of the public key.
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/rfc4034#section-5.1.4">RFC 4034 Section 5.1.4</a>
|
||||
*/
|
||||
@Transient
|
||||
@XmlJavaTypeAdapter(HexBinaryAdapter.class)
|
||||
byte[] digest;
|
||||
|
||||
public String getDomainRepoId() {
|
||||
return domainRepoId;
|
||||
}
|
||||
|
||||
public int getKeyTag() {
|
||||
return keyTag;
|
||||
}
|
||||
|
||||
public int getAlgorithm() {
|
||||
return algorithm;
|
||||
}
|
||||
|
||||
public int getDigestType() {
|
||||
return digestType;
|
||||
}
|
||||
|
||||
public byte[] getDigest() {
|
||||
return digest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the domain repository ID.
|
||||
*
|
||||
* <p>This method is private because it is only used by Hibernate.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private void setDomainRepoId(String domainRepoId) {
|
||||
this.domainRepoId = domainRepoId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key tag.
|
||||
*
|
||||
* <p>This method is private because it is only used by Hibernate.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private void setKeyTag(int keyTag) {
|
||||
this.keyTag = keyTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the algorithm.
|
||||
*
|
||||
* <p>This method is private because it is only used by Hibernate.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private void setAlgorithm(int algorithm) {
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the digest type.
|
||||
*
|
||||
* <p>This method is private because it is only used by Hibernate.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private void setDigestType(int digestType) {
|
||||
this.digestType = digestType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the digest.
|
||||
*
|
||||
* <p>This method is private because it is only used by Hibernate.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private void setDigest(byte[] digest) {
|
||||
this.digest = digest;
|
||||
}
|
||||
|
||||
public String getDigestAsString() {
|
||||
return digest == null ? "" : DatatypeConverter.printHexBinary(digest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the presentation format of this DS record.
|
||||
*
|
||||
* @see <a href="https://tools.ietf.org/html/rfc4034#section-5.3">RFC 4034 Section 5.3</a>
|
||||
*/
|
||||
public String toRrData() {
|
||||
return String.format(
|
||||
"%d %d %d %s",
|
||||
this.keyTag, this.algorithm, this.digestType, DatatypeConverter.printHexBinary(digest));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
// Copyright 2020 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.model.domain.secdns;
|
||||
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.ofy.ObjectifyService;
|
||||
import javax.persistence.Access;
|
||||
import javax.persistence.AccessType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
/** Entity class to represent a historic {@link DelegationSignerData}. */
|
||||
@Entity
|
||||
public class DomainDsDataHistory extends DomainDsDataBase {
|
||||
|
||||
@Id Long dsDataHistoryRevisionId;
|
||||
|
||||
/** ID of the {@link DomainHistory} entity that this entity is associated with. */
|
||||
@Column(nullable = false)
|
||||
Long domainHistoryRevisionId;
|
||||
|
||||
private DomainDsDataHistory() {}
|
||||
|
||||
/**
|
||||
* Creates a {@link DomainDsDataHistory} instance from given {@link #domainHistoryRevisionId} and
|
||||
* {@link DelegationSignerData} instance.
|
||||
*/
|
||||
public static DomainDsDataHistory createFrom(
|
||||
long domainHistoryRevisionId, DelegationSignerData dsData) {
|
||||
DomainDsDataHistory instance = new DomainDsDataHistory();
|
||||
instance.domainHistoryRevisionId = domainHistoryRevisionId;
|
||||
instance.domainRepoId = dsData.domainRepoId;
|
||||
instance.keyTag = dsData.getKeyTag();
|
||||
instance.algorithm = dsData.getAlgorithm();
|
||||
instance.digestType = dsData.getDigestType();
|
||||
instance.digest = dsData.getDigest();
|
||||
instance.dsDataHistoryRevisionId = ObjectifyService.allocateId();
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Access(AccessType.PROPERTY)
|
||||
public String getDomainRepoId() {
|
||||
return super.getDomainRepoId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Access(AccessType.PROPERTY)
|
||||
public int getKeyTag() {
|
||||
return super.getKeyTag();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Access(AccessType.PROPERTY)
|
||||
public int getAlgorithm() {
|
||||
return super.getAlgorithm();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Access(AccessType.PROPERTY)
|
||||
public int getDigestType() {
|
||||
return super.getDigestType();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Access(AccessType.PROPERTY)
|
||||
@Column(nullable = false)
|
||||
public byte[] getDigest() {
|
||||
return super.getDigest();
|
||||
}
|
||||
}
|
||||
@@ -61,7 +61,9 @@ public class HostHistory extends HistoryEntry implements SqlEntity {
|
||||
@Id
|
||||
@Access(AccessType.PROPERTY)
|
||||
public String getHostRepoId() {
|
||||
return parent.getName();
|
||||
// We need to handle null case here because Hibernate sometimes accesses this method before
|
||||
// parent gets initialized
|
||||
return parent == null ? null : parent.getName();
|
||||
}
|
||||
|
||||
/** This method is private because it is only used by Hibernate. */
|
||||
|
||||
@@ -20,7 +20,6 @@ import static google.registry.config.RegistryConfig.getEppResourceMaxCachedEntri
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.TypeUtils.instantiate;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
@@ -244,7 +243,7 @@ public abstract class ForeignKeyIndex<E extends EppResource> extends BackupGroup
|
||||
private static LoadingCache<Key<ForeignKeyIndex<?>>, Optional<ForeignKeyIndex<?>>>
|
||||
createForeignKeyIndexesCache(Duration expiry) {
|
||||
return CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(expiry.getMillis(), MILLISECONDS)
|
||||
.expireAfterWrite(java.time.Duration.ofMillis(expiry.getMillis()))
|
||||
.maximumSize(getEppResourceMaxCachedEntries())
|
||||
.build(CACHE_LOADER);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,9 @@ import com.google.common.base.Functions;
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.Result;
|
||||
import google.registry.model.contact.ContactHistory;
|
||||
import google.registry.model.host.HostHistory;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
@@ -102,12 +104,22 @@ public class DatastoreTransactionManager implements TransactionManager {
|
||||
|
||||
@Override
|
||||
public void insert(Object entity) {
|
||||
saveEntity(entity);
|
||||
put(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertAll(ImmutableCollection<?> entities) {
|
||||
getOfy().save().entities(entities);
|
||||
putAll(entities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertWithoutBackup(Object entity) {
|
||||
putWithoutBackup(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertAllWithoutBackup(ImmutableCollection<?> entities) {
|
||||
putAllWithoutBackup(entities);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -117,17 +129,37 @@ public class DatastoreTransactionManager implements TransactionManager {
|
||||
|
||||
@Override
|
||||
public void putAll(ImmutableCollection<?> entities) {
|
||||
getOfy().save().entities(entities);
|
||||
syncIfTransactionless(getOfy().save().entities(entities));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putWithoutBackup(Object entity) {
|
||||
syncIfTransactionless(getOfy().saveWithoutBackup().entities(entity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAllWithoutBackup(ImmutableCollection<?> entities) {
|
||||
syncIfTransactionless(getOfy().saveWithoutBackup().entities(entities));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Object entity) {
|
||||
saveEntity(entity);
|
||||
put(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAll(ImmutableCollection<?> entities) {
|
||||
getOfy().save().entities(entities);
|
||||
putAll(entities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateWithoutBackup(Object entity) {
|
||||
putWithoutBackup(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAllWithoutBackup(ImmutableCollection<?> entities) {
|
||||
putAllWithoutBackup(entities);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -158,6 +190,11 @@ public class DatastoreTransactionManager implements TransactionManager {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T load(T entity) {
|
||||
return ofy().load().entity(entity).now();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ImmutableMap<VKey<? extends T>, T> load(Iterable<? extends VKey<? extends T>> keys) {
|
||||
// Keep track of the Key -> VKey mapping so we can translate them back.
|
||||
@@ -175,13 +212,17 @@ public class DatastoreTransactionManager implements TransactionManager {
|
||||
|
||||
@Override
|
||||
public <T> ImmutableList<T> loadAll(Class<T> clazz) {
|
||||
// We can do a ofy().load().type(clazz), but this doesn't work in a transaction.
|
||||
throw new UnsupportedOperationException("Not available in the Datastore transaction manager");
|
||||
return ImmutableList.copyOf(getOfy().load().type(clazz));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ImmutableList<T> loadAll(Iterable<T> entities) {
|
||||
return ImmutableList.copyOf(getOfy().load().entities(entities).values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(VKey<?> key) {
|
||||
getOfy().delete().key(key.getOfyKey()).now();
|
||||
syncIfTransactionless(getOfy().delete().key(key.getOfyKey()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -192,7 +233,35 @@ public class DatastoreTransactionManager implements TransactionManager {
|
||||
StreamSupport.stream(vKeys.spliterator(), false)
|
||||
.map(VKey::getOfyKey)
|
||||
.collect(toImmutableList());
|
||||
getOfy().delete().keys(list).now();
|
||||
syncIfTransactionless(getOfy().delete().keys(list));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Object entity) {
|
||||
syncIfTransactionless(getOfy().delete().entity(entity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteWithoutBackup(VKey<?> key) {
|
||||
syncIfTransactionless(getOfy().deleteWithoutBackup().key(key.getOfyKey()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteWithoutBackup(Iterable<? extends VKey<?>> keys) {
|
||||
syncIfTransactionless(
|
||||
getOfy()
|
||||
.deleteWithoutBackup()
|
||||
.keys(Streams.stream(keys).map(VKey::getOfyKey).collect(toImmutableList())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteWithoutBackup(Object entity) {
|
||||
syncIfTransactionless(getOfy().deleteWithoutBackup().entity(entity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearSessionCache() {
|
||||
getOfy().clearSessionCache();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,7 +278,7 @@ public class DatastoreTransactionManager implements TransactionManager {
|
||||
if (entity instanceof HistoryEntry) {
|
||||
entity = ((HistoryEntry) entity).asHistoryEntry();
|
||||
}
|
||||
getOfy().save().entity(entity);
|
||||
syncIfTransactionless(getOfy().save().entity(entity));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -227,4 +296,19 @@ public class DatastoreTransactionManager implements TransactionManager {
|
||||
private <T> T loadNullable(VKey<T> key) {
|
||||
return toChildHistoryEntryIfPossible(getOfy().load().key(key.getOfyKey()).now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the given {@link Result} instance synchronously if not in a transaction.
|
||||
*
|
||||
* <p>The {@link Result} instance contains a task that will be executed by Objectify
|
||||
* asynchronously. If it is in a transaction, we don't need to execute the task immediately
|
||||
* because it is guaranteed to be done by the end of the transaction. However, if it is not in a
|
||||
* transaction, we need to execute it in case the following code expects that happens before
|
||||
* themselves.
|
||||
*/
|
||||
private void syncIfTransactionless(Result<?> result) {
|
||||
if (!inTransaction()) {
|
||||
result.now();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,17 +15,32 @@
|
||||
package google.registry.model.rde;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Verify.verify;
|
||||
import static com.google.common.base.Verify.verifyNotNull;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.model.rde.RdeNamingUtils.makePartialName;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
|
||||
import com.google.common.base.VerifyException;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
import com.googlecode.objectify.annotation.Id;
|
||||
import com.googlecode.objectify.annotation.Ignore;
|
||||
import google.registry.model.BackupGroupRoot;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.rde.RdeRevision.RdeRevisionId;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.persistence.converter.LocalDateConverter;
|
||||
import google.registry.schema.replay.DatastoreEntity;
|
||||
import google.registry.schema.replay.SqlEntity;
|
||||
import java.io.Serializable;
|
||||
import java.util.Optional;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Convert;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.IdClass;
|
||||
import javax.persistence.Transient;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
/**
|
||||
* Datastore entity for tracking RDE revisions.
|
||||
@@ -35,32 +50,67 @@ import org.joda.time.DateTime;
|
||||
* flag is included in the generated XML.
|
||||
*/
|
||||
@Entity
|
||||
public final class RdeRevision extends ImmutableObject {
|
||||
@javax.persistence.Entity
|
||||
@IdClass(RdeRevisionId.class)
|
||||
public final class RdeRevision extends BackupGroupRoot implements DatastoreEntity, SqlEntity {
|
||||
|
||||
/** String triplet of tld, date, and mode, e.g. {@code soy_2015-09-01_full}. */
|
||||
@Id
|
||||
String id;
|
||||
@Id @Transient String id;
|
||||
|
||||
@javax.persistence.Id @Ignore String tld;
|
||||
|
||||
@javax.persistence.Id @Ignore LocalDate date;
|
||||
|
||||
@javax.persistence.Id @Ignore RdeMode mode;
|
||||
|
||||
/**
|
||||
* Number of last revision successfully staged to GCS.
|
||||
*
|
||||
* <p>This values begins at zero upon object creation and thenceforth incremented transactionally.
|
||||
*/
|
||||
@Column(nullable = false)
|
||||
int revision;
|
||||
|
||||
/** Hibernate requires an empty constructor. */
|
||||
private RdeRevision() {}
|
||||
|
||||
public static RdeRevision create(
|
||||
String id, String tld, LocalDate date, RdeMode mode, int revision) {
|
||||
RdeRevision instance = new RdeRevision();
|
||||
instance.id = id;
|
||||
instance.tld = tld;
|
||||
instance.date = date;
|
||||
instance.mode = mode;
|
||||
instance.revision = revision;
|
||||
return instance;
|
||||
}
|
||||
|
||||
public int getRevision() {
|
||||
return revision;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<SqlEntity> toSqlEntities() {
|
||||
return ImmutableList.of(); // we don't care about RdeRevision history
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<DatastoreEntity> toDatastoreEntities() {
|
||||
return ImmutableList.of(); // we don't care about RdeRevision history
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns next revision ID to use when staging a new deposit file for the given triplet.
|
||||
*
|
||||
* @return {@code 0} for first deposit generation and {@code >0} for resends
|
||||
*/
|
||||
public static int getNextRevision(String tld, DateTime date, RdeMode mode) {
|
||||
RdeRevision object =
|
||||
ofy().load().type(RdeRevision.class).id(makePartialName(tld, date, mode)).now();
|
||||
return object == null ? 0 : object.revision + 1;
|
||||
String id = makePartialName(tld, date, mode);
|
||||
RdeRevisionId sqlKey = RdeRevisionId.create(tld, date.toLocalDate(), mode);
|
||||
Key<RdeRevision> ofyKey = Key.create(RdeRevision.class, id);
|
||||
Optional<RdeRevision> revisionOptional =
|
||||
tm().maybeLoad(VKey.create(RdeRevision.class, sqlKey, ofyKey));
|
||||
return revisionOptional.map(rdeRevision -> rdeRevision.revision + 1).orElse(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,17 +126,56 @@ public final class RdeRevision extends ImmutableObject {
|
||||
checkArgument(revision >= 0, "Negative revision: %s", revision);
|
||||
String triplet = makePartialName(tld, date, mode);
|
||||
tm().assertInTransaction();
|
||||
RdeRevision object = ofy().load().type(RdeRevision.class).id(triplet).now();
|
||||
RdeRevisionId sqlKey = RdeRevisionId.create(tld, date.toLocalDate(), mode);
|
||||
Key<RdeRevision> ofyKey = Key.create(RdeRevision.class, triplet);
|
||||
Optional<RdeRevision> revisionOptional =
|
||||
tm().maybeLoad(VKey.create(RdeRevision.class, sqlKey, ofyKey));
|
||||
if (revision == 0) {
|
||||
verify(object == null, "RdeRevision object already created: %s", object);
|
||||
revisionOptional.ifPresent(
|
||||
rdeRevision -> {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"RdeRevision object already created and revision 0 specified: %s",
|
||||
rdeRevision));
|
||||
});
|
||||
} else {
|
||||
verifyNotNull(object, "RDE revision object missing for %s?! revision=%s", triplet, revision);
|
||||
verify(object.revision == revision - 1,
|
||||
"RDE revision object should be at %s but was: %s", revision - 1, object);
|
||||
checkArgument(
|
||||
revisionOptional.isPresent(),
|
||||
"Couldn't find existing RDE revision %s when trying to save new revision %s",
|
||||
triplet,
|
||||
revision);
|
||||
checkArgument(
|
||||
revisionOptional.get().revision == revision - 1,
|
||||
"RDE revision object should be at revision %s but was: %s",
|
||||
revision - 1,
|
||||
revisionOptional.get());
|
||||
}
|
||||
RdeRevision object = RdeRevision.create(triplet, tld, date.toLocalDate(), mode, revision);
|
||||
tm().put(object);
|
||||
}
|
||||
|
||||
/** Class to represent the composite primary key of {@link RdeRevision} entity. */
|
||||
static class RdeRevisionId extends ImmutableObject implements Serializable {
|
||||
|
||||
String tld;
|
||||
|
||||
// Auto-conversion doesn't work for ID classes, we must specify @Column and @Convert
|
||||
@Column(columnDefinition = "date")
|
||||
@Convert(converter = LocalDateConverter.class)
|
||||
LocalDate date;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
RdeMode mode;
|
||||
|
||||
/** Hibernate requires this default constructor. */
|
||||
private RdeRevisionId() {}
|
||||
|
||||
static RdeRevisionId create(String tld, LocalDate date, RdeMode mode) {
|
||||
RdeRevisionId instance = new RdeRevisionId();
|
||||
instance.tld = tld;
|
||||
instance.date = date;
|
||||
instance.mode = mode;
|
||||
return instance;
|
||||
}
|
||||
object = new RdeRevision();
|
||||
object.id = triplet;
|
||||
object.revision = revision;
|
||||
ofy().save().entity(object);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.model.registry.Registries.assertTldsExist;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableSortedCopy;
|
||||
import static google.registry.util.PasswordUtils.SALT_SUPPLIER;
|
||||
@@ -704,10 +705,18 @@ public class Registrar extends ImmutableObject
|
||||
return new Builder(clone(this));
|
||||
}
|
||||
|
||||
/** Creates a {@link VKey} for this instance. */
|
||||
public VKey<Registrar> createVKey() {
|
||||
return VKey.create(Registrar.class, clientIdentifier, Key.create(this));
|
||||
}
|
||||
|
||||
/** Creates a {@link VKey} for the given {@code registrarId}. */
|
||||
public static VKey<Registrar> createVKey(String registrarId) {
|
||||
checkArgumentNotNull(registrarId, "registrarId must be specified");
|
||||
return VKey.create(
|
||||
Registrar.class, registrarId, Key.create(getCrossTldKey(), Registrar.class, registrarId));
|
||||
}
|
||||
|
||||
/** A builder for constructing {@link Registrar}, since it is immutable. */
|
||||
public static class Builder extends Buildable.Builder<Registrar> {
|
||||
public Builder() {}
|
||||
@@ -991,8 +1000,7 @@ public class Registrar extends ImmutableObject
|
||||
/** Loads and returns a registrar entity by its client id directly from Datastore. */
|
||||
public static Optional<Registrar> loadByClientId(String clientId) {
|
||||
checkArgument(!Strings.isNullOrEmpty(clientId), "clientId must be specified");
|
||||
return Optional.ofNullable(
|
||||
ofy().load().type(Registrar.class).parent(getCrossTldKey()).id(clientId).now());
|
||||
return transactIfJpaTm(() -> tm().maybeLoad(createVKey(clientId)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,6 +25,7 @@ import static google.registry.model.CacheUtils.memoizeWithShortExpiration;
|
||||
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.persistence.transaction.TransactionManagerUtil.ofyOrJpaTm;
|
||||
import static google.registry.util.CollectionUtils.entriesToImmutableMap;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
@@ -59,15 +60,21 @@ public final class Registries {
|
||||
tm().doTransactionless(
|
||||
() -> {
|
||||
ImmutableSet<String> tlds =
|
||||
ofy()
|
||||
.load()
|
||||
.type(Registry.class)
|
||||
.ancestor(getCrossTldKey())
|
||||
.keys()
|
||||
.list()
|
||||
.stream()
|
||||
.map(Key::getName)
|
||||
.collect(toImmutableSet());
|
||||
ofyOrJpaTm(
|
||||
() ->
|
||||
ofy()
|
||||
.load()
|
||||
.type(Registry.class)
|
||||
.ancestor(getCrossTldKey())
|
||||
.keys()
|
||||
.list()
|
||||
.stream()
|
||||
.map(Key::getName)
|
||||
.collect(toImmutableSet()),
|
||||
() ->
|
||||
tm().loadAll(Registry.class).stream()
|
||||
.map(Registry::getTldStr)
|
||||
.collect(toImmutableSet()));
|
||||
return Registry.getAll(tlds).stream()
|
||||
.map(e -> Maps.immutableEntry(e.getTldStr(), e.getTldType()))
|
||||
.collect(entriesToImmutableMap());
|
||||
|
||||
@@ -22,13 +22,11 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.collect.Maps.toMap;
|
||||
import static google.registry.config.RegistryConfig.getSingletonCacheRefreshDuration;
|
||||
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
@@ -62,6 +60,7 @@ import google.registry.model.domain.fee.BaseFee.FeeType;
|
||||
import google.registry.model.domain.fee.Fee;
|
||||
import google.registry.model.registry.label.PremiumList;
|
||||
import google.registry.model.registry.label.ReservedList;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.schema.replay.DatastoreAndSqlEntity;
|
||||
import google.registry.util.Idn;
|
||||
import java.util.Map;
|
||||
@@ -260,35 +259,32 @@ public class Registry extends ImmutableObject implements Buildable, DatastoreAnd
|
||||
/** A cache that loads the {@link Registry} for a given tld. */
|
||||
private static final LoadingCache<String, Optional<Registry>> CACHE =
|
||||
CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(getSingletonCacheRefreshDuration().getMillis(), MILLISECONDS)
|
||||
.expireAfterWrite(
|
||||
java.time.Duration.ofMillis(getSingletonCacheRefreshDuration().getMillis()))
|
||||
.build(
|
||||
new CacheLoader<String, Optional<Registry>>() {
|
||||
@Override
|
||||
public Optional<Registry> load(final String tld) {
|
||||
// Enter a transaction-less context briefly; we don't want to enroll every TLD in
|
||||
// a transaction that might be wrapping this call.
|
||||
return Optional.ofNullable(
|
||||
tm().doTransactionless(
|
||||
() ->
|
||||
ofy()
|
||||
.load()
|
||||
.key(Key.create(getCrossTldKey(), Registry.class, tld))
|
||||
.now()));
|
||||
return tm().doTransactionless(() -> tm().maybeLoad(createVKey(tld)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Optional<Registry>> loadAll(Iterable<? extends String> tlds) {
|
||||
ImmutableMap<String, Key<Registry>> keysMap =
|
||||
toMap(
|
||||
ImmutableSet.copyOf(tlds),
|
||||
tld -> Key.create(getCrossTldKey(), Registry.class, tld));
|
||||
Map<Key<Registry>, Registry> entities =
|
||||
tm().doTransactionless(() -> ofy().load().keys(keysMap.values()));
|
||||
ImmutableMap<String, VKey<Registry>> keysMap =
|
||||
toMap(ImmutableSet.copyOf(tlds), Registry::createVKey);
|
||||
Map<VKey<? extends Registry>, Registry> entities =
|
||||
tm().doTransactionless(() -> tm().load(keysMap.values()));
|
||||
return Maps.transformEntries(
|
||||
keysMap, (k, v) -> Optional.ofNullable(entities.getOrDefault(v, null)));
|
||||
}
|
||||
});
|
||||
|
||||
public static VKey<Registry> createVKey(String tld) {
|
||||
return VKey.create(Registry.class, tld, Key.create(getCrossTldKey(), Registry.class, tld));
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the pricing engine that this TLD uses.
|
||||
*
|
||||
@@ -386,7 +382,7 @@ public class Registry extends ImmutableObject implements Buildable, DatastoreAnd
|
||||
CreateAutoTimestamp creationTime = CreateAutoTimestamp.create(null);
|
||||
|
||||
/** The set of reserved lists that are applicable to this registry. */
|
||||
@Column(name = "reserved_list_names", nullable = false)
|
||||
@Column(name = "reserved_list_names")
|
||||
Set<Key<ReservedList>> reservedLists;
|
||||
|
||||
/** Retrieves an ImmutableSet of all ReservedLists associated with this tld. */
|
||||
|
||||
@@ -25,7 +25,6 @@ import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
import static google.registry.model.ofy.ObjectifyService.allocateId;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Splitter;
|
||||
@@ -197,7 +196,7 @@ public final class PremiumList extends BaseDomainLabelList<Money, PremiumList.Pr
|
||||
@VisibleForTesting
|
||||
static LoadingCache<String, PremiumList> createCachePremiumLists(Duration cachePersistDuration) {
|
||||
return CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(cachePersistDuration.getMillis(), MILLISECONDS)
|
||||
.expireAfterWrite(java.time.Duration.ofMillis(cachePersistDuration.getMillis()))
|
||||
.build(
|
||||
new CacheLoader<String, PremiumList>() {
|
||||
@Override
|
||||
@@ -221,7 +220,8 @@ public final class PremiumList extends BaseDomainLabelList<Money, PremiumList.Pr
|
||||
static final LoadingCache<Key<PremiumListRevision>, PremiumListRevision>
|
||||
cachePremiumListRevisions =
|
||||
CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(getSingletonCachePersistDuration().getMillis(), MILLISECONDS)
|
||||
.expireAfterWrite(
|
||||
java.time.Duration.ofMillis(getSingletonCachePersistDuration().getMillis()))
|
||||
.build(
|
||||
new CacheLoader<Key<PremiumListRevision>, PremiumListRevision>() {
|
||||
@Override
|
||||
@@ -260,14 +260,14 @@ public final class PremiumList extends BaseDomainLabelList<Money, PremiumList.Pr
|
||||
static LoadingCache<Key<PremiumListEntry>, Optional<PremiumListEntry>>
|
||||
createCachePremiumListEntries(Duration cachePersistDuration) {
|
||||
return CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(cachePersistDuration.getMillis(), MILLISECONDS)
|
||||
.expireAfterWrite(java.time.Duration.ofMillis(cachePersistDuration.getMillis()))
|
||||
.maximumSize(getStaticPremiumListMaxCachedEntries())
|
||||
.build(
|
||||
new CacheLoader<Key<PremiumListEntry>, Optional<PremiumListEntry>>() {
|
||||
@Override
|
||||
public Optional<PremiumListEntry> load(final Key<PremiumListEntry> entryKey) {
|
||||
return tm()
|
||||
.doTransactionless(() -> Optional.ofNullable(ofy().load().key(entryKey).now()));
|
||||
return tm().doTransactionless(
|
||||
() -> Optional.ofNullable(ofy().load().key(entryKey).now()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static google.registry.config.RegistryConfig.getDomainLabelListCacheDuration;
|
||||
import static google.registry.model.registry.label.ReservationType.FULLY_BLOCKED;
|
||||
import static google.registry.util.CollectionUtils.nullToEmpty;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
@@ -241,7 +240,8 @@ public final class ReservedList
|
||||
|
||||
private static LoadingCache<String, ReservedList> cache =
|
||||
CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(getDomainLabelListCacheDuration().getMillis(), MILLISECONDS)
|
||||
.expireAfterWrite(
|
||||
java.time.Duration.ofMillis(getDomainLabelListCacheDuration().getMillis()))
|
||||
.build(
|
||||
new CacheLoader<String, ReservedList>() {
|
||||
@Override
|
||||
|
||||
@@ -193,7 +193,7 @@ public class HistoryEntry extends ImmutableObject implements Buildable, Datastor
|
||||
* transaction counts (such as contact or host mutations).
|
||||
*/
|
||||
@Transient // domain-specific
|
||||
Set<DomainTransactionRecord> domainTransactionRecords;
|
||||
protected Set<DomainTransactionRecord> domainTransactionRecords;
|
||||
|
||||
public long getId() {
|
||||
// For some reason, Hibernate throws NPE during some initialization phase if we don't deal with
|
||||
@@ -273,7 +273,8 @@ public class HistoryEntry extends ImmutableObject implements Buildable, Datastor
|
||||
/** This method exists solely to satisfy Hibernate. Use the {@link Builder} instead. */
|
||||
@SuppressWarnings("UnusedMethod")
|
||||
private void setDomainTransactionRecords(Set<DomainTransactionRecord> domainTransactionRecords) {
|
||||
this.domainTransactionRecords = ImmutableSet.copyOf(domainTransactionRecords);
|
||||
this.domainTransactionRecords =
|
||||
domainTransactionRecords == null ? null : ImmutableSet.copyOf(domainTransactionRecords);
|
||||
}
|
||||
|
||||
public static VKey<HistoryEntry> createVKey(Key<HistoryEntry> key) {
|
||||
|
||||
@@ -75,7 +75,7 @@ public class Spec11ThreatMatch extends ImmutableObject implements Buildable, Sql
|
||||
String registrarId;
|
||||
|
||||
/** Date on which the check was run, on which the domain was flagged as abusive. */
|
||||
@Column(nullable = false)
|
||||
@Column(nullable = false, columnDefinition = "date")
|
||||
LocalDate checkDate;
|
||||
|
||||
/** The domain's top-level domain. */
|
||||
|
||||
@@ -16,23 +16,25 @@ package google.registry.model.reporting;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.persistence.transaction.JpaTransactionManager;
|
||||
import google.registry.util.DateTimeUtils;
|
||||
import javax.persistence.TemporalType;
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
/**
|
||||
* Data access object for {@link google.registry.model.reporting.Spec11ThreatMatch}.
|
||||
*
|
||||
* <p>A JpaTransactionManager is passed into each static method because they are called from a BEAM
|
||||
* pipeline and we don't know where it's coming from.</p>
|
||||
* pipeline and we don't know where it's coming from.
|
||||
*/
|
||||
public class Spec11ThreatMatchDao {
|
||||
|
||||
|
||||
/** Delete all entries with the specified date from the database. */
|
||||
public static void deleteEntriesByDate(JpaTransactionManager jpaTm, LocalDate date) {
|
||||
jpaTm.assertInTransaction();
|
||||
jpaTm
|
||||
.getEntityManager()
|
||||
.createQuery("DELETE FROM Spec11ThreatMatch WHERE check_date = :date")
|
||||
.setParameter("date", date.toString())
|
||||
.setParameter("date", DateTimeUtils.toSqlDate(date), TemporalType.DATE)
|
||||
.executeUpdate();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ package google.registry.model.server;
|
||||
|
||||
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
import com.googlecode.objectify.annotation.Id;
|
||||
@@ -23,11 +24,13 @@ import com.googlecode.objectify.annotation.Parent;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.annotations.ReportedOn;
|
||||
import google.registry.model.common.EntityGroupRoot;
|
||||
import google.registry.schema.replay.DatastoreEntity;
|
||||
import google.registry.schema.replay.SqlEntity;
|
||||
|
||||
/** Pointer to the latest {@link KmsSecretRevision}. */
|
||||
@Entity
|
||||
@ReportedOn
|
||||
public class KmsSecret extends ImmutableObject {
|
||||
public class KmsSecret extends ImmutableObject implements DatastoreEntity {
|
||||
|
||||
/** The unique name of this {@link KmsSecret}. */
|
||||
@Id String name;
|
||||
@@ -45,6 +48,11 @@ public class KmsSecret extends ImmutableObject {
|
||||
return latestRevision;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<SqlEntity> toSqlEntities() {
|
||||
return ImmutableList.of(); // not persisted in SQL
|
||||
}
|
||||
|
||||
public static KmsSecret create(String name, KmsSecretRevision latestRevision) {
|
||||
KmsSecret instance = new KmsSecret();
|
||||
instance.name = name;
|
||||
|
||||
@@ -17,14 +17,24 @@ package google.registry.model.server;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
import com.googlecode.objectify.annotation.Id;
|
||||
import com.googlecode.objectify.annotation.Ignore;
|
||||
import com.googlecode.objectify.annotation.OnLoad;
|
||||
import com.googlecode.objectify.annotation.Parent;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.CreateAutoTimestamp;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.annotations.ReportedOn;
|
||||
import google.registry.schema.replay.DatastoreEntity;
|
||||
import google.registry.schema.replay.SqlEntity;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.PostLoad;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
/**
|
||||
* An encrypted value.
|
||||
@@ -35,13 +45,22 @@ import google.registry.model.annotations.ReportedOn;
|
||||
*
|
||||
* <p>The value can be encrypted and decrypted using Cloud KMS.
|
||||
*
|
||||
* <p>Note that the primary key of this entity is {@link #revisionKey}, which is auto-generated by
|
||||
* the database. So, if a retry of insertion happens after the previous attempt unexpectedly
|
||||
* succeeds, we will end up with having two exact same revisions that differ only by revisionKey.
|
||||
* This is fine though, because we only use the revision with the highest revisionKey.
|
||||
*
|
||||
* <p>TODO: remove Datastore-specific fields post-Registry-3.0-migration and rename to KmsSecret.
|
||||
*
|
||||
* @see <a href="https://cloud.google.com/kms/docs/">Google Cloud Key Management Service
|
||||
* Documentation</a>
|
||||
* @see google.registry.keyring.kms.KmsKeyring
|
||||
*/
|
||||
@Entity
|
||||
@ReportedOn
|
||||
public class KmsSecretRevision extends ImmutableObject {
|
||||
@javax.persistence.Entity(name = "KmsSecret")
|
||||
@Table(indexes = {@Index(columnList = "secretName")})
|
||||
public class KmsSecretRevision extends ImmutableObject implements DatastoreEntity, SqlEntity {
|
||||
|
||||
/**
|
||||
* The maximum allowable secret size. Although Datastore allows entities up to 1 MB in size,
|
||||
@@ -49,18 +68,31 @@ public class KmsSecretRevision extends ImmutableObject {
|
||||
*/
|
||||
private static final int MAX_SECRET_SIZE_BYTES = 64 * 1024 * 1024;
|
||||
|
||||
/** The revision of this secret. */
|
||||
@Id long revisionKey;
|
||||
/**
|
||||
* The revision of this secret.
|
||||
*
|
||||
* <p>TODO: change name of the variable to revisionId once we're off Datastore
|
||||
*/
|
||||
@Id
|
||||
@javax.persistence.Id
|
||||
@Column(name = "revisionId")
|
||||
long revisionKey;
|
||||
|
||||
/** The parent {@link KmsSecret} which contains metadata about this {@link KmsSecretRevision}. */
|
||||
@Parent Key<KmsSecret> parent;
|
||||
@Parent @Transient Key<KmsSecret> parent;
|
||||
@Column(nullable = false)
|
||||
@Ignore
|
||||
String secretName;
|
||||
|
||||
/**
|
||||
* The name of the {@code cryptoKeyVersion} associated with this {@link KmsSecretRevision}.
|
||||
*
|
||||
* <p>TODO: change name of the variable to cryptoKeyVersionName once we're off Datastore
|
||||
*
|
||||
* @see <a
|
||||
* href="https://cloud.google.com/kms/docs/reference/rest/v1/projects.locations.keyRings.cryptoKeys.cryptoKeyVersions">projects.locations.keyRings.cryptoKeys.cryptoKeyVersions</a>
|
||||
*/
|
||||
@Column(nullable = false, name = "cryptoKeyVersionName")
|
||||
String kmsCryptoKeyVersionName;
|
||||
|
||||
/**
|
||||
@@ -70,9 +102,11 @@ public class KmsSecretRevision extends ImmutableObject {
|
||||
* @see <a
|
||||
* href="https://cloud.google.com/kms/docs/reference/rest/v1/projects.locations.keyRings.cryptoKeys/encrypt">projects.locations.keyRings.cryptoKeys.encrypt</a>
|
||||
*/
|
||||
@Column(nullable = false)
|
||||
String encryptedValue;
|
||||
|
||||
/** An automatically managed creation timestamp. */
|
||||
@Column(nullable = false)
|
||||
CreateAutoTimestamp creationTime = CreateAutoTimestamp.create(null);
|
||||
|
||||
public String getKmsCryptoKeyVersionName() {
|
||||
@@ -83,6 +117,28 @@ public class KmsSecretRevision extends ImmutableObject {
|
||||
return encryptedValue;
|
||||
}
|
||||
|
||||
// When loading from SQL, fill out the Datastore-specific field
|
||||
@PostLoad
|
||||
void postLoad() {
|
||||
parent = Key.create(getCrossTldKey(), KmsSecret.class, secretName);
|
||||
}
|
||||
|
||||
// When loading from Datastore, fill out the SQL-specific field
|
||||
@OnLoad
|
||||
void onLoad() {
|
||||
secretName = parent.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<SqlEntity> toSqlEntities() {
|
||||
return ImmutableList.of(); // This is dually-written, as we do not care about history
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<DatastoreEntity> toDatastoreEntities() {
|
||||
return ImmutableList.of(); // This is dually-written, as we do not care about history
|
||||
}
|
||||
|
||||
/** A builder for constructing {@link KmsSecretRevision} entities, since they are immutable. */
|
||||
public static class Builder extends Buildable.Builder<KmsSecretRevision> {
|
||||
|
||||
@@ -108,6 +164,7 @@ public class KmsSecretRevision extends ImmutableObject {
|
||||
*/
|
||||
public Builder setParent(String secretName) {
|
||||
getInstance().parent = Key.create(getCrossTldKey(), KmsSecret.class, secretName);
|
||||
getInstance().secretName = secretName;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright 2020 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.model.server;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* A {@link KmsSecretRevision} DAO for Cloud SQL.
|
||||
*
|
||||
* <p>TODO: Rename this class to KmsSecretDao after migrating to Cloud SQL.
|
||||
*/
|
||||
public class KmsSecretRevisionSqlDao {
|
||||
|
||||
private KmsSecretRevisionSqlDao() {}
|
||||
|
||||
/** Saves the given KMS secret revision. */
|
||||
public static void save(KmsSecretRevision kmsSecretRevision) {
|
||||
checkArgumentNotNull(kmsSecretRevision, "kmsSecretRevision cannot be null");
|
||||
jpaTm().assertInTransaction();
|
||||
jpaTm().put(kmsSecretRevision);
|
||||
}
|
||||
|
||||
/** Returns the latest revision for the secret name given, or absent if nonexistent. */
|
||||
public static Optional<KmsSecretRevision> getLatestRevision(String secretName) {
|
||||
checkArgument(!isNullOrEmpty(secretName), "secretName cannot be null or empty");
|
||||
jpaTm().assertInTransaction();
|
||||
return jpaTm()
|
||||
.getEntityManager()
|
||||
.createQuery(
|
||||
"FROM KmsSecret ks WHERE ks.revisionKey IN (SELECT MAX(revisionKey) FROM "
|
||||
+ "KmsSecret subKs WHERE subKs.secretName = :secretName)",
|
||||
KmsSecretRevision.class)
|
||||
.setParameter("secretName", secretName)
|
||||
.getResultStream()
|
||||
.findFirst();
|
||||
}
|
||||
}
|
||||
@@ -28,8 +28,12 @@ import static google.registry.util.DateTimeUtils.isBeforeOrAt;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.MapDifference;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.EmbedMap;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
@@ -41,8 +45,19 @@ import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.annotations.NotBackedUp;
|
||||
import google.registry.model.annotations.NotBackedUp.Reason;
|
||||
import google.registry.model.common.EntityGroupRoot;
|
||||
import google.registry.schema.replay.DatastoreEntity;
|
||||
import google.registry.schema.replay.SqlEntity;
|
||||
import google.registry.util.CollectionUtils;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.MapKeyColumn;
|
||||
import javax.persistence.Transient;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
@@ -56,35 +71,50 @@ import org.joda.time.DateTime;
|
||||
* order to avoid exceeding the one megabyte max entity size limit, we'll also be sharding that
|
||||
* entity into multiple entities, each entity containing {@value #SHARD_SIZE} rows.
|
||||
*
|
||||
* <p>TODO: We can remove the sharding once we have converted entirely to Cloud SQL storage during
|
||||
* the Registry 3.0 migration. Then, the entire table will be stored conceptually as one entity (in
|
||||
* fact in SignedMarkRevocationList and SignedMarkRevocationEntry tables).
|
||||
*
|
||||
* @see google.registry.tmch.SmdrlCsvParser
|
||||
* @see <a href="http://tools.ietf.org/html/draft-lozano-tmch-func-spec-08#section-6.2">
|
||||
* TMCH functional specifications - SMD Revocation List</a>
|
||||
* @see <a href="http://tools.ietf.org/html/draft-lozano-tmch-func-spec-08#section-6.2">TMCH
|
||||
* functional specifications - SMD Revocation List</a>
|
||||
*/
|
||||
@Entity
|
||||
@javax.persistence.Entity
|
||||
@NotBackedUp(reason = Reason.EXTERNALLY_SOURCED)
|
||||
public class SignedMarkRevocationList extends ImmutableObject {
|
||||
public class SignedMarkRevocationList extends ImmutableObject
|
||||
implements DatastoreEntity, SqlEntity {
|
||||
|
||||
@VisibleForTesting
|
||||
static final int SHARD_SIZE = 10000;
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
@VisibleForTesting static final int SHARD_SIZE = 10000;
|
||||
|
||||
/** Common ancestor for queries. */
|
||||
@Parent
|
||||
Key<EntityGroupRoot> parent = getCrossTldKey();
|
||||
@Parent @Transient Key<EntityGroupRoot> parent = getCrossTldKey();
|
||||
|
||||
/** ID for the sharded entity. */
|
||||
@Id
|
||||
long id;
|
||||
@Id @Transient long id;
|
||||
|
||||
@Ignore
|
||||
@javax.persistence.Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
Long revisionId;
|
||||
|
||||
/** Time when this list was last updated, as specified in the first line of the CSV file. */
|
||||
DateTime creationTime;
|
||||
|
||||
/** A map from SMD IDs to revocation time. */
|
||||
@EmbedMap
|
||||
@ElementCollection
|
||||
@CollectionTable(
|
||||
name = "SignedMarkRevocationEntry",
|
||||
joinColumns = @JoinColumn(name = "revisionId", referencedColumnName = "revisionId"))
|
||||
@MapKeyColumn(name = "smdId")
|
||||
@Column(name = "revocationTime", nullable = false)
|
||||
Map</*@MatchesPattern("[0-9]+-[0-9]+")*/ String, DateTime> revokes;
|
||||
|
||||
/** Indicates that this is a shard rather than a "full" list. */
|
||||
@Ignore
|
||||
boolean isShard;
|
||||
@Ignore @Transient boolean isShard;
|
||||
|
||||
/**
|
||||
* A cached supplier that fetches the SMDRL shards from Datastore and recombines them into a
|
||||
@@ -92,32 +122,16 @@ public class SignedMarkRevocationList extends ImmutableObject {
|
||||
*/
|
||||
private static final Supplier<SignedMarkRevocationList> CACHE =
|
||||
memoizeWithShortExpiration(
|
||||
() ->
|
||||
tm()
|
||||
.transactNewReadOnly(
|
||||
() -> {
|
||||
Iterable<SignedMarkRevocationList> shards =
|
||||
ofy()
|
||||
.load()
|
||||
.type(SignedMarkRevocationList.class)
|
||||
.ancestor(getCrossTldKey());
|
||||
DateTime creationTime =
|
||||
isEmpty(shards)
|
||||
? START_OF_TIME
|
||||
: checkNotNull(
|
||||
Iterables.get(shards, 0).creationTime, "creationTime");
|
||||
ImmutableMap.Builder<String, DateTime> revokes =
|
||||
new ImmutableMap.Builder<>();
|
||||
for (SignedMarkRevocationList shard : shards) {
|
||||
revokes.putAll(shard.revokes);
|
||||
checkState(
|
||||
creationTime.equals(shard.creationTime),
|
||||
"Inconsistent creation times: %s vs. %s",
|
||||
creationTime,
|
||||
shard.creationTime);
|
||||
}
|
||||
return create(creationTime, revokes.build());
|
||||
}));
|
||||
() -> {
|
||||
SignedMarkRevocationList datastoreList = loadFromDatastore();
|
||||
// Also load the list from Cloud SQL, compare the two lists, and log if different.
|
||||
try {
|
||||
loadAndCompareCloudSqlList(datastoreList);
|
||||
} catch (Throwable t) {
|
||||
logger.atSevere().withCause(t).log("Error comparing signed mark revocation lists.");
|
||||
}
|
||||
return datastoreList;
|
||||
});
|
||||
|
||||
/** Return a single logical instance that combines all Datastore shards. */
|
||||
public static SignedMarkRevocationList get() {
|
||||
@@ -149,10 +163,39 @@ public class SignedMarkRevocationList extends ImmutableObject {
|
||||
return revokes.size();
|
||||
}
|
||||
|
||||
/** Save this list to Datastore in sharded form. Returns {@code this}. */
|
||||
/** Save this list to Datastore in sharded form and to Cloud SQL. Returns {@code this}. */
|
||||
public SignedMarkRevocationList save() {
|
||||
tm()
|
||||
.transact(
|
||||
saveToDatastore();
|
||||
SignedMarkRevocationListDao.trySave(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Loads the shards from Datastore and combines them into one list. */
|
||||
private static SignedMarkRevocationList loadFromDatastore() {
|
||||
return tm().transactNewReadOnly(
|
||||
() -> {
|
||||
Iterable<SignedMarkRevocationList> shards =
|
||||
ofy().load().type(SignedMarkRevocationList.class).ancestor(getCrossTldKey());
|
||||
DateTime creationTime =
|
||||
isEmpty(shards)
|
||||
? START_OF_TIME
|
||||
: checkNotNull(Iterables.get(shards, 0).creationTime, "creationTime");
|
||||
ImmutableMap.Builder<String, DateTime> revokes = new ImmutableMap.Builder<>();
|
||||
for (SignedMarkRevocationList shard : shards) {
|
||||
revokes.putAll(shard.revokes);
|
||||
checkState(
|
||||
creationTime.equals(shard.creationTime),
|
||||
"Inconsistent creation times: %s vs. %s",
|
||||
creationTime,
|
||||
shard.creationTime);
|
||||
}
|
||||
return create(creationTime, revokes.build());
|
||||
});
|
||||
}
|
||||
|
||||
/** Save this list to Datastore in sharded form. */
|
||||
private SignedMarkRevocationList saveToDatastore() {
|
||||
tm().transact(
|
||||
() -> {
|
||||
ofy()
|
||||
.deleteWithoutBackup()
|
||||
@@ -165,8 +208,7 @@ public class SignedMarkRevocationList extends ImmutableObject {
|
||||
ofy()
|
||||
.saveWithoutBackup()
|
||||
.entities(
|
||||
CollectionUtils.partitionMap(revokes, SHARD_SIZE)
|
||||
.stream()
|
||||
CollectionUtils.partitionMap(revokes, SHARD_SIZE).stream()
|
||||
.map(
|
||||
shardRevokes -> {
|
||||
SignedMarkRevocationList shard = create(creationTime, shardRevokes);
|
||||
@@ -180,6 +222,38 @@ public class SignedMarkRevocationList extends ImmutableObject {
|
||||
return this;
|
||||
}
|
||||
|
||||
private static void loadAndCompareCloudSqlList(SignedMarkRevocationList datastoreList) {
|
||||
// Lifted with some modifications from ClaimsListShard
|
||||
Optional<SignedMarkRevocationList> maybeCloudSqlList =
|
||||
SignedMarkRevocationListDao.getLatestRevision();
|
||||
if (maybeCloudSqlList.isPresent()) {
|
||||
SignedMarkRevocationList cloudSqlList = maybeCloudSqlList.get();
|
||||
MapDifference<String, DateTime> diff =
|
||||
Maps.difference(datastoreList.revokes, cloudSqlList.revokes);
|
||||
if (!diff.areEqual()) {
|
||||
if (diff.entriesDiffering().size() > 10) {
|
||||
logger.atWarning().log(
|
||||
String.format(
|
||||
"Unequal SM revocation lists detected, Cloud SQL list with revision id %d has %d"
|
||||
+ " different records than the current Datastore list.",
|
||||
cloudSqlList.revisionId, diff.entriesDiffering().size()));
|
||||
} else {
|
||||
StringBuilder diffMessage = new StringBuilder("Unequal SM revocation lists detected:\n");
|
||||
diff.entriesDiffering()
|
||||
.forEach(
|
||||
(label, valueDiff) ->
|
||||
diffMessage.append(
|
||||
String.format(
|
||||
"SMD %s has key %s in Datastore and key %s in Cloud SQL.\n",
|
||||
label, valueDiff.leftValue(), valueDiff.rightValue())));
|
||||
logger.atWarning().log(diffMessage.toString());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.atWarning().log("Signed mark revocation list in Cloud SQL is empty.");
|
||||
}
|
||||
}
|
||||
|
||||
/** As a safety mechanism, fail if someone tries to save this class directly. */
|
||||
@OnSave
|
||||
void disallowUnshardedSaves() {
|
||||
@@ -188,6 +262,16 @@ public class SignedMarkRevocationList extends ImmutableObject {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<SqlEntity> toSqlEntities() {
|
||||
return ImmutableList.of(); // Dually-written every day
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<DatastoreEntity> toDatastoreEntities() {
|
||||
return ImmutableList.of(); // Dually-written every day
|
||||
}
|
||||
|
||||
/** Exception when trying to directly save a {@link SignedMarkRevocationList} without sharding. */
|
||||
public static class UnshardedSaveException extends RuntimeException {}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright 2020 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.model.smd;
|
||||
|
||||
import static google.registry.model.CacheUtils.memoizeWithShortExpiration;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import java.util.Optional;
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
public class SignedMarkRevocationListDao {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
private static final Supplier<Optional<SignedMarkRevocationList>> CACHE =
|
||||
memoizeWithShortExpiration(SignedMarkRevocationListDao::getLatestRevision);
|
||||
|
||||
/** Returns the most recent revision of the {@link SignedMarkRevocationList}, from cache. */
|
||||
public static Optional<SignedMarkRevocationList> getLatestRevisionCached() {
|
||||
return CACHE.get();
|
||||
}
|
||||
|
||||
public static Optional<SignedMarkRevocationList> getLatestRevision() {
|
||||
return jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
EntityManager em = jpaTm().getEntityManager();
|
||||
Long revisionId =
|
||||
em.createQuery("SELECT MAX(revisionId) FROM SignedMarkRevocationList", Long.class)
|
||||
.getSingleResult();
|
||||
return em.createQuery(
|
||||
"FROM SignedMarkRevocationList smrl LEFT JOIN FETCH smrl.revokes "
|
||||
+ "WHERE smrl.revisionId = :revisionId",
|
||||
SignedMarkRevocationList.class)
|
||||
.setParameter("revisionId", revisionId)
|
||||
.getResultStream()
|
||||
.findFirst();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to save the given {@link SignedMarkRevocationList} into Cloud SQL. If the save fails, the
|
||||
* error will be logged but no exception will be thrown.
|
||||
*
|
||||
* <p>This method is used during the dual-write phase of database migration as Datastore is still
|
||||
* the authoritative database.
|
||||
*/
|
||||
static void trySave(SignedMarkRevocationList signedMarkRevocationList) {
|
||||
try {
|
||||
SignedMarkRevocationListDao.save(signedMarkRevocationList);
|
||||
logger.atInfo().log(
|
||||
"Inserted %,d signed mark revocations into Cloud SQL",
|
||||
signedMarkRevocationList.revokes.size());
|
||||
} catch (Throwable e) {
|
||||
logger.atSevere().withCause(e).log("Error inserting signed mark revocations into Cloud SQL");
|
||||
}
|
||||
}
|
||||
|
||||
private static void save(SignedMarkRevocationList signedMarkRevocationList) {
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(signedMarkRevocationList));
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,6 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
@@ -146,8 +145,7 @@ public class ClaimsListShard extends ImmutableObject implements DatastoreAndSqlE
|
||||
|
||||
private static final Retrier LOADER_RETRIER = new Retrier(new SystemSleeper(), 2);
|
||||
|
||||
private static final Callable<ClaimsListShard> LOADER_CALLABLE =
|
||||
() -> {
|
||||
private static ClaimsListShard loadClaimsListShard() {
|
||||
// Find the most recent revision.
|
||||
Key<ClaimsListRevision> revisionKey = getCurrentRevision();
|
||||
|
||||
@@ -246,7 +244,9 @@ public class ClaimsListShard extends ImmutableObject implements DatastoreAndSqlE
|
||||
*/
|
||||
private static final Supplier<ClaimsListShard> CACHE =
|
||||
memoizeWithShortExpiration(
|
||||
() -> LOADER_RETRIER.callWithRetry(LOADER_CALLABLE, IllegalStateException.class));
|
||||
() ->
|
||||
LOADER_RETRIER.callWithRetry(
|
||||
ClaimsListShard::loadClaimsListShard, IllegalStateException.class));
|
||||
|
||||
/** Returns the revision id of this claims list, or throws exception if it is null. */
|
||||
public Long getRevisionId() {
|
||||
|
||||
@@ -14,12 +14,16 @@
|
||||
|
||||
package google.registry.model.transfer;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.AlsoLoad;
|
||||
import com.googlecode.objectify.annotation.Embed;
|
||||
import com.googlecode.objectify.annotation.Ignore;
|
||||
import com.googlecode.objectify.annotation.IgnoreSave;
|
||||
import com.googlecode.objectify.annotation.Unindex;
|
||||
import com.googlecode.objectify.condition.IfNull;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.domain.Period;
|
||||
import google.registry.model.domain.Period.Unit;
|
||||
import google.registry.model.poll.PollMessage;
|
||||
@@ -86,6 +90,10 @@ public class DomainTransferData extends TransferData<DomainTransferData.Builder>
|
||||
@Column(name = "transfer_billing_event_id")
|
||||
VKey<BillingEvent.OneTime> serverApproveBillingEvent;
|
||||
|
||||
@Ignore
|
||||
@Column(name = "transfer_billing_event_history_id")
|
||||
Long serverApproveBillingEventHistoryId;
|
||||
|
||||
/**
|
||||
* The autorenew billing event that should be associated with this resource after the transfer.
|
||||
*
|
||||
@@ -96,6 +104,10 @@ public class DomainTransferData extends TransferData<DomainTransferData.Builder>
|
||||
@Column(name = "transfer_billing_recurrence_id")
|
||||
VKey<BillingEvent.Recurring> serverApproveAutorenewEvent;
|
||||
|
||||
@Ignore
|
||||
@Column(name = "transfer_billing_recurrence_history_id")
|
||||
Long serverApproveAutorenewEventHistoryId;
|
||||
|
||||
/**
|
||||
* The autorenew poll message that should be associated with this resource after the transfer.
|
||||
*
|
||||
@@ -106,11 +118,50 @@ public class DomainTransferData extends TransferData<DomainTransferData.Builder>
|
||||
@Column(name = "transfer_autorenew_poll_message_id")
|
||||
VKey<PollMessage.Autorenew> serverApproveAutorenewPollMessage;
|
||||
|
||||
@Ignore
|
||||
@Column(name = "transfer_autorenew_poll_message_history_id")
|
||||
Long serverApproveAutorenewPollMessageHistoryId;
|
||||
|
||||
@Override
|
||||
public Builder copyConstantFieldsToBuilder() {
|
||||
return super.copyConstantFieldsToBuilder().setTransferPeriod(this.transferPeriod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the set of ofy keys after loading from SQL using the specified {@code rootKey}.
|
||||
*
|
||||
* <p>This is for use by DomainBase/DomainHistory PostLoad methods ONLY.
|
||||
*/
|
||||
public void restoreOfyKeys(Key<DomainBase> rootKey) {
|
||||
serverApproveBillingEvent =
|
||||
DomainBase.restoreOfyFrom(
|
||||
rootKey, serverApproveBillingEvent, serverApproveBillingEventHistoryId);
|
||||
serverApproveAutorenewEvent =
|
||||
DomainBase.restoreOfyFrom(
|
||||
rootKey, serverApproveAutorenewEvent, serverApproveAutorenewEventHistoryId);
|
||||
serverApproveAutorenewPollMessage =
|
||||
DomainBase.restoreOfyFrom(
|
||||
rootKey, serverApproveAutorenewPollMessage, serverApproveAutorenewPollMessageHistoryId);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused") // For Hibernate.
|
||||
private void loadServerApproveBillingEventHistoryId(
|
||||
@AlsoLoad("serverApproveBillingEvent") VKey<BillingEvent.OneTime> val) {
|
||||
serverApproveBillingEventHistoryId = DomainBase.getHistoryId(val);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused") // For Hibernate.
|
||||
private void loadServerApproveAutorenewEventHistoryId(
|
||||
@AlsoLoad("serverApproveAutorenewEvent") VKey<BillingEvent.Recurring> val) {
|
||||
serverApproveAutorenewEventHistoryId = DomainBase.getHistoryId(val);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused") // For Hibernate.
|
||||
private void loadServerApproveAutorenewPollMessageHistoryId(
|
||||
@AlsoLoad("serverApproveAutorenewPollMessage") VKey<PollMessage.Autorenew> val) {
|
||||
serverApproveAutorenewPollMessageHistoryId = DomainBase.getHistoryId(val);
|
||||
}
|
||||
|
||||
public Period getTransferPeriod() {
|
||||
return transferPeriod;
|
||||
}
|
||||
@@ -125,16 +176,34 @@ public class DomainTransferData extends TransferData<DomainTransferData.Builder>
|
||||
return serverApproveBillingEvent;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@Nullable
|
||||
public Long getServerApproveBillingEventHistoryId() {
|
||||
return serverApproveBillingEventHistoryId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public VKey<BillingEvent.Recurring> getServerApproveAutorenewEvent() {
|
||||
return serverApproveAutorenewEvent;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@Nullable
|
||||
public Long getServerApproveAutorenewEventHistoryId() {
|
||||
return serverApproveAutorenewEventHistoryId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public VKey<PollMessage.Autorenew> getServerApproveAutorenewPollMessage() {
|
||||
return serverApproveAutorenewPollMessage;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@Nullable
|
||||
public Long getServerApproveAutorenewPollMessageHistoryId() {
|
||||
return serverApproveAutorenewPollMessageHistoryId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return EMPTY.equals(this);
|
||||
@@ -168,18 +237,24 @@ public class DomainTransferData extends TransferData<DomainTransferData.Builder>
|
||||
public Builder setServerApproveBillingEvent(
|
||||
VKey<BillingEvent.OneTime> serverApproveBillingEvent) {
|
||||
getInstance().serverApproveBillingEvent = serverApproveBillingEvent;
|
||||
getInstance().serverApproveBillingEventHistoryId =
|
||||
DomainBase.getHistoryId(serverApproveBillingEvent);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setServerApproveAutorenewEvent(
|
||||
VKey<BillingEvent.Recurring> serverApproveAutorenewEvent) {
|
||||
getInstance().serverApproveAutorenewEvent = serverApproveAutorenewEvent;
|
||||
getInstance().serverApproveAutorenewEventHistoryId =
|
||||
DomainBase.getHistoryId(serverApproveAutorenewEvent);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setServerApproveAutorenewPollMessage(
|
||||
VKey<PollMessage.Autorenew> serverApproveAutorenewPollMessage) {
|
||||
getInstance().serverApproveAutorenewPollMessage = serverApproveAutorenewPollMessage;
|
||||
getInstance().serverApproveAutorenewPollMessageHistoryId =
|
||||
DomainBase.getHistoryId(serverApproveAutorenewPollMessage);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import google.registry.request.RequestHandler;
|
||||
import google.registry.util.SystemClock;
|
||||
import java.io.IOException;
|
||||
import java.security.Security;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -51,13 +50,16 @@ public class ServletBase extends HttpServlet {
|
||||
// etc), we log the error but keep the main thread running. Also the shutdown hook will only be
|
||||
// registered if metric reporter starts up correctly.
|
||||
try {
|
||||
metricReporter.get().startAsync().awaitRunning(10, TimeUnit.SECONDS);
|
||||
metricReporter.get().startAsync().awaitRunning(java.time.Duration.ofSeconds(10));
|
||||
logger.atInfo().log("Started up MetricReporter");
|
||||
LifecycleManager.getInstance()
|
||||
.setShutdownHook(
|
||||
() -> {
|
||||
try {
|
||||
metricReporter.get().stopAsync().awaitTerminated(10, TimeUnit.SECONDS);
|
||||
metricReporter
|
||||
.get()
|
||||
.stopAsync()
|
||||
.awaitTerminated(java.time.Duration.ofSeconds(10));
|
||||
logger.atInfo().log("Shut down MetricReporter");
|
||||
} catch (TimeoutException e) {
|
||||
logger.atSevere().withCause(e).log("Failed to stop MetricReporter.");
|
||||
|
||||
@@ -14,17 +14,23 @@
|
||||
|
||||
package google.registry.persistence.converter;
|
||||
|
||||
import google.registry.util.DateTimeUtils;
|
||||
import java.sql.Date;
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Converter;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.format.ISODateTimeFormat;
|
||||
|
||||
/** JPA converter for {@link LocalDate}. */
|
||||
/** JPA converter for {@link LocalDate}, to/from {@link Date}. */
|
||||
@Converter(autoApply = true)
|
||||
public class LocalDateConverter extends ToStringConverterBase<LocalDate> {
|
||||
public class LocalDateConverter implements AttributeConverter<LocalDate, Date> {
|
||||
|
||||
/** Converts the string (a date in ISO-8601 format) into a LocalDate. */
|
||||
@Override
|
||||
public LocalDate convertToEntityAttribute(String columnValue) {
|
||||
return (columnValue == null) ? null : LocalDate.parse(columnValue, ISODateTimeFormat.date());
|
||||
public Date convertToDatabaseColumn(LocalDate attribute) {
|
||||
return attribute == null ? null : DateTimeUtils.toSqlDate(attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDate convertToEntityAttribute(Date dbData) {
|
||||
return dbData == null ? null : DateTimeUtils.toLocalDate(dbData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package google.registry.persistence.transaction;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
@@ -25,6 +26,7 @@ import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.config.RegistryConfig;
|
||||
import google.registry.persistence.JpaRetries;
|
||||
@@ -238,6 +240,16 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
|
||||
entities.forEach(this::insert);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertWithoutBackup(Object entity) {
|
||||
insert(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertAllWithoutBackup(ImmutableCollection<?> entities) {
|
||||
insertAll(entities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Object entity) {
|
||||
checkArgumentNotNull(entity, "entity must be specified");
|
||||
@@ -253,6 +265,16 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
|
||||
entities.forEach(this::put);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putWithoutBackup(Object entity) {
|
||||
put(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAllWithoutBackup(ImmutableCollection<?> entities) {
|
||||
putAll(entities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Object entity) {
|
||||
checkArgumentNotNull(entity, "entity must be specified");
|
||||
@@ -269,6 +291,16 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
|
||||
entities.forEach(this::update);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateWithoutBackup(Object entity) {
|
||||
update(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAllWithoutBackup(ImmutableCollection<?> entities) {
|
||||
updateAll(entities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> boolean exists(VKey<T> key) {
|
||||
checkArgumentNotNull(key, "key must be specified");
|
||||
@@ -315,6 +347,14 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T load(T entity) {
|
||||
checkArgumentNotNull(entity, "entity must be specified");
|
||||
assertInTransaction();
|
||||
return (T)
|
||||
load(VKey.createSql(entity.getClass(), emf.getPersistenceUnitUtil().getIdentifier(entity)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ImmutableMap<VKey<? extends T>, T> load(Iterable<? extends VKey<? extends T>> keys) {
|
||||
checkArgumentNotNull(keys, "keys must be specified");
|
||||
@@ -342,6 +382,11 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
|
||||
.getResultList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ImmutableList<T> loadAll(Iterable<T> entities) {
|
||||
return Streams.stream(entities).map(this::load).collect(toImmutableList());
|
||||
}
|
||||
|
||||
private int internalDelete(VKey<?> key) {
|
||||
checkArgumentNotNull(key, "key must be specified");
|
||||
assertInTransaction();
|
||||
@@ -366,6 +411,37 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
|
||||
vKeys.forEach(this::internalDelete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Object entity) {
|
||||
checkArgumentNotNull(entity, "entity must be specified");
|
||||
assertInTransaction();
|
||||
Object managedEntity = entity;
|
||||
if (!getEntityManager().contains(entity)) {
|
||||
managedEntity = getEntityManager().merge(entity);
|
||||
}
|
||||
getEntityManager().remove(managedEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteWithoutBackup(VKey<?> key) {
|
||||
delete(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteWithoutBackup(Iterable<? extends VKey<?>> keys) {
|
||||
delete(keys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteWithoutBackup(Object entity) {
|
||||
delete(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearSessionCache() {
|
||||
// This is an intended no-op method as there is no session cache in Postgresql.
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void assertDelete(VKey<T> key) {
|
||||
if (internalDelete(key) != 1) {
|
||||
|
||||
@@ -91,18 +91,90 @@ public interface TransactionManager {
|
||||
/** Persists all new entities in the database, throws exception if any entity already exists. */
|
||||
void insertAll(ImmutableCollection<?> entities);
|
||||
|
||||
/**
|
||||
* Persists a new entity in the database without writing any backup if the underlying database is
|
||||
* Datastore.
|
||||
*
|
||||
* <p>This method is for the sake of keeping a single code path when replacing ofy() with tm() in
|
||||
* the application code. When the method is invoked with Datastore, it won't write the commit log
|
||||
* backup; when invoked with Cloud SQL, it behaves the same as the method which doesn't have
|
||||
* "WithoutBackup" in its method name because it is not necessary to have the backup mechanism in
|
||||
* SQL.
|
||||
*/
|
||||
void insertWithoutBackup(Object entity);
|
||||
|
||||
/**
|
||||
* Persists all new entities in the database without writing any backup if the underlying database
|
||||
* is Datastore.
|
||||
*
|
||||
* <p>This method is for the sake of keeping a single code path when replacing ofy() with tm() in
|
||||
* the application code. When the method is invoked with Datastore, it won't write the commit log
|
||||
* backup; when invoked with Cloud SQL, it behaves the same as the method which doesn't have
|
||||
* "WithoutBackup" in its method name because it is not necessary to have the backup mechanism in
|
||||
* SQL.
|
||||
*/
|
||||
void insertAllWithoutBackup(ImmutableCollection<?> entities);
|
||||
|
||||
/** Persists a new entity or update the existing entity in the database. */
|
||||
void put(Object entity);
|
||||
|
||||
/** Persists all new entities or update the existing entities in the database. */
|
||||
void putAll(ImmutableCollection<?> entities);
|
||||
|
||||
/**
|
||||
* Persists a new entity or update the existing entity in the database without writing any backup
|
||||
* if the underlying database is Datastore.
|
||||
*
|
||||
* <p>This method is for the sake of keeping a single code path when replacing ofy() with tm() in
|
||||
* the application code. When the method is invoked with Datastore, it won't write the commit log
|
||||
* backup; when invoked with Cloud SQL, it behaves the same as the method which doesn't have
|
||||
* "WithoutBackup" in its method name because it is not necessary to have the backup mechanism in
|
||||
* SQL.
|
||||
*/
|
||||
void putWithoutBackup(Object entity);
|
||||
|
||||
/**
|
||||
* Persists all new entities or update the existing entities in the database without writing any
|
||||
* backup if the underlying database is Datastore.
|
||||
*
|
||||
* <p>This method is for the sake of keeping a single code path when replacing ofy() with tm() in
|
||||
* the application code. When the method is invoked with Datastore, it won't write the commit log
|
||||
* backup; when invoked with Cloud SQL, it behaves the same as the method which doesn't have
|
||||
* "WithoutBackup" in its method name because it is not necessary to have the backup mechanism in
|
||||
* SQL.
|
||||
*/
|
||||
void putAllWithoutBackup(ImmutableCollection<?> entities);
|
||||
|
||||
/** Updates an entity in the database, throws exception if the entity does not exist. */
|
||||
void update(Object entity);
|
||||
|
||||
/** Updates all entities in the database, throws exception if any entity does not exist. */
|
||||
void updateAll(ImmutableCollection<?> entities);
|
||||
|
||||
/**
|
||||
* Updates an entity in the database without writing any backup if the underlying database is
|
||||
* Datastore.
|
||||
*
|
||||
* <p>This method is for the sake of keeping a single code path when replacing ofy() with tm() in
|
||||
* the application code. When the method is invoked with Datastore, it won't write the commit log
|
||||
* backup; when invoked with Cloud SQL, it behaves the same as the method which doesn't have
|
||||
* "WithoutBackup" in its method name because it is not necessary to have the backup mechanism in
|
||||
* SQL.
|
||||
*/
|
||||
void updateWithoutBackup(Object entity);
|
||||
|
||||
/**
|
||||
* Updates all entities in the database without writing any backup if the underlying database is
|
||||
* Datastore.
|
||||
*
|
||||
* <p>This method is for the sake of keeping a single code path when replacing ofy() with tm() in
|
||||
* the application code. When the method is invoked with Datastore, it won't write the commit log
|
||||
* backup; when invoked with Cloud SQL, it behaves the same as the method which doesn't have
|
||||
* "WithoutBackup" in its method name because it is not necessary to have the backup mechanism in
|
||||
* SQL.
|
||||
*/
|
||||
void updateAllWithoutBackup(ImmutableCollection<?> entities);
|
||||
|
||||
/** Returns whether the given entity with same ID exists. */
|
||||
boolean exists(Object entity);
|
||||
|
||||
@@ -115,6 +187,11 @@ public interface TransactionManager {
|
||||
/** Loads the entity by its id, throws NoSuchElementException if it doesn't exist. */
|
||||
<T> T load(VKey<T> key);
|
||||
|
||||
/**
|
||||
* Loads the given entity from the database, throws NoSuchElementException if it doesn't exist.
|
||||
*/
|
||||
<T> T load(T entity);
|
||||
|
||||
/**
|
||||
* Loads the set of entities by their key id.
|
||||
*
|
||||
@@ -125,9 +202,38 @@ public interface TransactionManager {
|
||||
/** Loads all entities of the given type, returns empty if there is no such entity. */
|
||||
<T> ImmutableList<T> loadAll(Class<T> clazz);
|
||||
|
||||
/**
|
||||
* Loads all given entities from the database, throws NoSuchElementException if it doesn't exist.
|
||||
*/
|
||||
<T> ImmutableList<T> loadAll(Iterable<T> entities);
|
||||
|
||||
/** Deletes the entity by its id. */
|
||||
void delete(VKey<?> key);
|
||||
|
||||
/** Deletes the set of entities by their key id. */
|
||||
void delete(Iterable<? extends VKey<?>> keys);
|
||||
|
||||
/** Deletes the given entity from the database. */
|
||||
void delete(Object entity);
|
||||
|
||||
/**
|
||||
* Deletes the entity by its id without writing any backup if the underlying database is
|
||||
* Datastore.
|
||||
*/
|
||||
void deleteWithoutBackup(VKey<?> key);
|
||||
|
||||
/**
|
||||
* Deletes the set of entities by their key id without writing any backup if the underlying
|
||||
* database is Datastore.
|
||||
*/
|
||||
void deleteWithoutBackup(Iterable<? extends VKey<?>> keys);
|
||||
|
||||
/**
|
||||
* Deletes the given entity from the database without writing any backup if the underlying
|
||||
* database is Datastore.
|
||||
*/
|
||||
void deleteWithoutBackup(Object entity);
|
||||
|
||||
/** Clears the session cache if the underlying database is Datastore, otherwise it is a no-op. */
|
||||
void clearSessionCache();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
// Copyright 2020 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 google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
|
||||
import google.registry.model.ofy.DatastoreTransactionManager;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/** Utility class that provides supplementary methods for {@link TransactionManager}. */
|
||||
public class TransactionManagerUtil {
|
||||
|
||||
/**
|
||||
* Returns the result of the given {@link Supplier}.
|
||||
*
|
||||
* <p>If {@link TransactionManagerFactory#tm()} returns a {@link JpaTransactionManager} instance,
|
||||
* the {@link Supplier} is executed in a transaction.
|
||||
*/
|
||||
public static <T> T transactIfJpaTm(Supplier<T> supplier) {
|
||||
if (tm() instanceof JpaTransactionManager) {
|
||||
return tm().transact(supplier);
|
||||
} else {
|
||||
return supplier.get();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the given {@link Runnable}.
|
||||
*
|
||||
* <p>If {@link TransactionManagerFactory#tm()} returns a {@link JpaTransactionManager} instance,
|
||||
* the {@link Runnable} is executed in a transaction.
|
||||
*/
|
||||
public static void transactIfJpaTm(Runnable runnable) {
|
||||
transactIfJpaTm(
|
||||
() -> {
|
||||
runnable.run();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes either {@code ofyRunnable} if {@link TransactionManagerFactory#tm()} returns a {@link
|
||||
* JpaTransactionManager} instance, or {@code jpaRunnable} if {@link
|
||||
* TransactionManagerFactory#tm()} returns a {@link DatastoreTransactionManager} instance.
|
||||
*/
|
||||
public static void ofyOrJpaTm(Runnable ofyRunnable, Runnable jpaRunnable) {
|
||||
ofyOrJpaTm(
|
||||
() -> {
|
||||
ofyRunnable.run();
|
||||
return null;
|
||||
},
|
||||
() -> {
|
||||
jpaRunnable.run();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the result from either {@code ofySupplier} if {@link TransactionManagerFactory#tm()}
|
||||
* returns a {@link JpaTransactionManager} instance, or {@code jpaSupplier} if {@link
|
||||
* TransactionManagerFactory#tm()} returns a {@link DatastoreTransactionManager} instance.
|
||||
*/
|
||||
public static <T> T ofyOrJpaTm(Supplier<T> ofySupplier, Supplier<T> jpaSupplier) {
|
||||
if (tm() instanceof DatastoreTransactionManager) {
|
||||
return ofySupplier.get();
|
||||
} else if (tm() instanceof JpaTransactionManager) {
|
||||
return jpaSupplier.get();
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
"Expected tm() to be DatastoreTransactionManager or JpaTransactionManager, but got "
|
||||
+ tm().getClass());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the given {@link Runnable} if {@link TransactionManagerFactory#tm()} returns a {@link
|
||||
* DatastoreTransactionManager} instance, otherwise does nothing.
|
||||
*/
|
||||
public static void ofyTmOrDoNothing(Runnable ofyRunnable) {
|
||||
if (tm() instanceof DatastoreTransactionManager) {
|
||||
ofyRunnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the result from the given {@link Supplier} if {@link TransactionManagerFactory#tm()}
|
||||
* returns a {@link DatastoreTransactionManager} instance, otherwise returns null.
|
||||
*/
|
||||
public static <T> T ofyTmOrDoNothing(Supplier<T> ofySupplier) {
|
||||
if (tm() instanceof DatastoreTransactionManager) {
|
||||
return ofySupplier.get();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private TransactionManagerUtil() {}
|
||||
}
|
||||
@@ -18,7 +18,6 @@ import static google.registry.config.RegistryConfig.getDomainLabelListCacheDurat
|
||||
import static google.registry.config.RegistryConfig.getSingletonCachePersistDuration;
|
||||
import static google.registry.config.RegistryConfig.getStaticPremiumListMaxCachedEntries;
|
||||
import static google.registry.schema.tld.PremiumListDao.getPriceForLabel;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
@@ -48,7 +47,7 @@ class PremiumListCache {
|
||||
static LoadingCache<String, Optional<PremiumList>> createCachePremiumLists(
|
||||
Duration cachePersistDuration) {
|
||||
return CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(cachePersistDuration.getMillis(), MILLISECONDS)
|
||||
.expireAfterWrite(java.time.Duration.ofMillis(cachePersistDuration.getMillis()))
|
||||
.build(
|
||||
new CacheLoader<String, Optional<PremiumList>>() {
|
||||
@Override
|
||||
@@ -81,7 +80,7 @@ class PremiumListCache {
|
||||
static LoadingCache<RevisionIdAndLabel, Optional<BigDecimal>> createCachePremiumEntries(
|
||||
Duration cachePersistDuration) {
|
||||
return CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(cachePersistDuration.getMillis(), MILLISECONDS)
|
||||
.expireAfterWrite(java.time.Duration.ofMillis(cachePersistDuration.getMillis()))
|
||||
.maximumSize(getStaticPremiumListMaxCachedEntries())
|
||||
.build(
|
||||
new CacheLoader<RevisionIdAndLabel, Optional<BigDecimal>>() {
|
||||
|
||||
@@ -18,7 +18,6 @@ import static google.registry.config.RegistryConfig.ConfigModule.TmchCaMode.PILO
|
||||
import static google.registry.config.RegistryConfig.ConfigModule.TmchCaMode.PRODUCTION;
|
||||
import static google.registry.config.RegistryConfig.getSingletonCacheRefreshDuration;
|
||||
import static google.registry.util.ResourceUtils.readResourceUtf8;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
@@ -77,7 +76,8 @@ public final class TmchCertificateAuthority {
|
||||
*/
|
||||
private static final LoadingCache<TmchCaMode, X509CRL> CRL_CACHE =
|
||||
CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(getSingletonCacheRefreshDuration().getMillis(), MILLISECONDS)
|
||||
.expireAfterWrite(
|
||||
java.time.Duration.ofMillis(getSingletonCacheRefreshDuration().getMillis()))
|
||||
.build(
|
||||
new CacheLoader<TmchCaMode, X509CRL>() {
|
||||
@Override
|
||||
|
||||
@@ -18,7 +18,6 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Sets.SetView;
|
||||
import java.io.File;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Compares two Datastore backups in V3 format on local file system. This is for use in tests and
|
||||
@@ -30,8 +29,10 @@ import java.util.function.Predicate;
|
||||
*/
|
||||
class CompareDbBackups {
|
||||
private static final String DS_V3_BACKUP_FILE_PREFIX = "output-";
|
||||
private static final Predicate<File> DATA_FILE_MATCHER =
|
||||
file -> file.isFile() && file.getName().startsWith(DS_V3_BACKUP_FILE_PREFIX);
|
||||
|
||||
private static boolean isDatastoreV3File(File file) {
|
||||
return file.isFile() && file.getName().startsWith(DS_V3_BACKUP_FILE_PREFIX);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (args.length != 2) {
|
||||
@@ -40,9 +41,11 @@ class CompareDbBackups {
|
||||
}
|
||||
|
||||
ImmutableSet<EntityWrapper> entities1 =
|
||||
RecordAccumulator.readDirectory(new File(args[0]), DATA_FILE_MATCHER).getEntityWrapperSet();
|
||||
RecordAccumulator.readDirectory(new File(args[0]), CompareDbBackups::isDatastoreV3File)
|
||||
.getEntityWrapperSet();
|
||||
ImmutableSet<EntityWrapper> entities2 =
|
||||
RecordAccumulator.readDirectory(new File(args[1]), DATA_FILE_MATCHER).getEntityWrapperSet();
|
||||
RecordAccumulator.readDirectory(new File(args[1]), CompareDbBackups::isDatastoreV3File)
|
||||
.getEntityWrapperSet();
|
||||
|
||||
// Calculate the entities added and removed.
|
||||
SetView<EntityWrapper> added = Sets.difference(entities2, entities1);
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.flows.certs.CertificateChecker;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registrar.RegistrarAddress;
|
||||
import google.registry.model.registry.Registry;
|
||||
@@ -49,6 +50,7 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
@@ -57,9 +59,9 @@ abstract class CreateOrUpdateRegistrarCommand extends MutatingCommand {
|
||||
|
||||
static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
@Parameter(
|
||||
description = "Client identifier of the registrar account",
|
||||
required = true)
|
||||
@Inject CertificateChecker certificateChecker;
|
||||
|
||||
@Parameter(description = "Client identifier of the registrar account", required = true)
|
||||
List<String> mainParameters;
|
||||
|
||||
@Parameter(
|
||||
@@ -356,11 +358,21 @@ abstract class CreateOrUpdateRegistrarCommand extends MutatingCommand {
|
||||
}
|
||||
if (clientCertificateFilename != null) {
|
||||
String asciiCert = new String(Files.readAllBytes(clientCertificateFilename), US_ASCII);
|
||||
// An empty certificate file is allowed in order to provide a functionality for removing an
|
||||
// existing certificate without providing a replacement. An uploaded empty certificate file
|
||||
// will prevent the registrar from being able to establish EPP connections.
|
||||
if (!asciiCert.equals("")) {
|
||||
certificateChecker.validateCertificate(asciiCert);
|
||||
}
|
||||
builder.setClientCertificate(asciiCert, now);
|
||||
}
|
||||
|
||||
if (failoverClientCertificateFilename != null) {
|
||||
String asciiCert =
|
||||
new String(Files.readAllBytes(failoverClientCertificateFilename), US_ASCII);
|
||||
if (!asciiCert.equals("")) {
|
||||
certificateChecker.validateCertificate(asciiCert);
|
||||
}
|
||||
builder.setFailoverClientCertificate(asciiCert, now);
|
||||
}
|
||||
if (!isNullOrEmpty(clientCertificateHash)) {
|
||||
|
||||
@@ -83,42 +83,83 @@ import javax.inject.Singleton;
|
||||
})
|
||||
interface RegistryToolComponent {
|
||||
void inject(AckPollMessagesCommand command);
|
||||
|
||||
void inject(CheckDomainClaimsCommand command);
|
||||
|
||||
void inject(CheckDomainCommand command);
|
||||
|
||||
void inject(CountDomainsCommand command);
|
||||
|
||||
void inject(CreateAnchorTenantCommand command);
|
||||
|
||||
void inject(CreateCdnsTld command);
|
||||
|
||||
void inject(CreateContactCommand command);
|
||||
|
||||
void inject(CreateDomainCommand command);
|
||||
|
||||
void inject(CreateRegistrarCommand command);
|
||||
|
||||
void inject(CreateTldCommand command);
|
||||
|
||||
void inject(DeployInvoicingPipelineCommand command);
|
||||
|
||||
void inject(DeploySpec11PipelineCommand command);
|
||||
|
||||
void inject(EncryptEscrowDepositCommand command);
|
||||
|
||||
void inject(GenerateAllocationTokensCommand command);
|
||||
|
||||
void inject(GenerateDnsReportCommand command);
|
||||
|
||||
void inject(GenerateEscrowDepositCommand command);
|
||||
|
||||
void inject(GetKeyringSecretCommand command);
|
||||
|
||||
void inject(GetOperationStatusCommand command);
|
||||
|
||||
void inject(GhostrydeCommand command);
|
||||
|
||||
void inject(ImportDatastoreCommand command);
|
||||
|
||||
void inject(ListCursorsCommand command);
|
||||
|
||||
void inject(ListDatastoreOperationsCommand command);
|
||||
|
||||
void inject(LoadSnapshotCommand command);
|
||||
|
||||
void inject(LockDomainCommand command);
|
||||
|
||||
void inject(LoginCommand command);
|
||||
|
||||
void inject(LogoutCommand command);
|
||||
|
||||
void inject(PendingEscrowCommand command);
|
||||
|
||||
void inject(RenewDomainCommand command);
|
||||
|
||||
void inject(SendEscrowReportToIcannCommand command);
|
||||
|
||||
void inject(SetNumInstancesCommand command);
|
||||
|
||||
void inject(SetupOteCommand command);
|
||||
|
||||
void inject(UnlockDomainCommand command);
|
||||
|
||||
void inject(UnrenewDomainCommand command);
|
||||
|
||||
void inject(UpdateCursorsCommand command);
|
||||
|
||||
void inject(UpdateDomainCommand command);
|
||||
|
||||
void inject(UpdateKmsKeyringCommand command);
|
||||
|
||||
void inject(UpdateRegistrarCommand command);
|
||||
|
||||
void inject(UpdateTldCommand command);
|
||||
|
||||
void inject(ValidateEscrowDepositCommand command);
|
||||
|
||||
void inject(WhoisQueryCommand command);
|
||||
|
||||
AppEngineConnection appEngineConnection();
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.flows.certs.CertificateChecker;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registrar.RegistrarContact;
|
||||
import google.registry.model.registrar.RegistrarContact.Type;
|
||||
@@ -64,7 +65,6 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
@@ -93,11 +93,13 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
||||
@Inject SendEmailUtils sendEmailUtils;
|
||||
@Inject AuthenticatedRegistrarAccessor registrarAccessor;
|
||||
@Inject AuthResult authResult;
|
||||
@Inject CertificateChecker certificateChecker;
|
||||
|
||||
@Inject RegistrarSettingsAction() {}
|
||||
|
||||
private static final Predicate<RegistrarContact> HAS_PHONE =
|
||||
contact -> contact.getPhoneNumber() != null;
|
||||
private static boolean hasPhone(RegistrarContact contact) {
|
||||
return contact.getPhoneNumber() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -306,19 +308,43 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
||||
RegistrarFormFields.IP_ADDRESS_ALLOW_LIST_FIELD
|
||||
.extractUntyped(args)
|
||||
.orElse(ImmutableList.of()));
|
||||
RegistrarFormFields.CLIENT_CERTIFICATE_FIELD
|
||||
.extractUntyped(args)
|
||||
.ifPresent(
|
||||
certificate -> builder.setClientCertificate(certificate, tm().getTransactionTime()));
|
||||
RegistrarFormFields.FAILOVER_CLIENT_CERTIFICATE_FIELD
|
||||
.extractUntyped(args)
|
||||
.ifPresent(
|
||||
certificate ->
|
||||
builder.setFailoverClientCertificate(certificate, tm().getTransactionTime()));
|
||||
|
||||
Optional<String> certificateString =
|
||||
RegistrarFormFields.CLIENT_CERTIFICATE_FIELD.extractUntyped(args);
|
||||
if (certificateString.isPresent()) {
|
||||
if (validateCertificate(initialRegistrar.getClientCertificate(), certificateString.get())) {
|
||||
builder.setClientCertificate(certificateString.get(), tm().getTransactionTime());
|
||||
}
|
||||
}
|
||||
|
||||
Optional<String> failoverCertificateString =
|
||||
RegistrarFormFields.FAILOVER_CLIENT_CERTIFICATE_FIELD.extractUntyped(args);
|
||||
if (failoverCertificateString.isPresent()) {
|
||||
if (validateCertificate(
|
||||
initialRegistrar.getFailoverClientCertificate(), failoverCertificateString.get())) {
|
||||
builder.setFailoverClientCertificate(
|
||||
failoverCertificateString.get(), tm().getTransactionTime());
|
||||
}
|
||||
}
|
||||
|
||||
return checkNotChangedUnlessAllowed(builder, initialRegistrar, Role.OWNER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the registrar should accept the new certificate. Returns false if the
|
||||
* certificate is already the one stored for the registrar.
|
||||
*/
|
||||
private boolean validateCertificate(String existingCertificate, String certificateString) {
|
||||
if ((existingCertificate == null) || !existingCertificate.equals(certificateString)) {
|
||||
// TODO(sarhabot): remove this check after November 1, 2020
|
||||
if (tm().getTransactionTime().isAfter(DateTime.parse("2020-11-01T00:00:00Z"))) {
|
||||
certificateChecker.validateCertificate(certificateString);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a registrar with the ADMIN-controlled args from the http request.
|
||||
*
|
||||
@@ -512,8 +538,8 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
||||
Multimap<Type, RegistrarContact> newContactsByType,
|
||||
Type... types) {
|
||||
for (Type type : types) {
|
||||
if (oldContactsByType.get(type).stream().anyMatch(HAS_PHONE)
|
||||
&& newContactsByType.get(type).stream().noneMatch(HAS_PHONE)) {
|
||||
if (oldContactsByType.get(type).stream().anyMatch(RegistrarSettingsAction::hasPhone)
|
||||
&& newContactsByType.get(type).stream().noneMatch(RegistrarSettingsAction::hasPhone)) {
|
||||
throw new ContactRequirementException(
|
||||
String.format(
|
||||
"Please provide a phone number for at least one %s contact",
|
||||
|
||||
@@ -47,12 +47,14 @@
|
||||
<class>google.registry.model.domain.DomainHistory</class>
|
||||
<class>google.registry.model.domain.GracePeriod</class>
|
||||
<class>google.registry.model.domain.secdns.DelegationSignerData</class>
|
||||
<class>google.registry.model.domain.secdns.DomainDsDataHistory</class>
|
||||
<class>google.registry.model.domain.token.AllocationToken</class>
|
||||
<class>google.registry.model.host.HostHistory</class>
|
||||
<class>google.registry.model.host.HostResource</class>
|
||||
<class>google.registry.model.poll.PollMessage</class>
|
||||
<class>google.registry.model.poll.PollMessage$OneTime</class>
|
||||
<class>google.registry.model.poll.PollMessage$Autorenew</class>
|
||||
<class>google.registry.model.rde.RdeRevision</class>
|
||||
<class>google.registry.model.registrar.Registrar</class>
|
||||
<class>google.registry.model.registrar.RegistrarContact</class>
|
||||
<class>google.registry.model.registry.label.PremiumList</class>
|
||||
@@ -60,6 +62,8 @@
|
||||
<class>google.registry.model.registry.Registry</class>
|
||||
<class>google.registry.model.reporting.DomainTransactionRecord</class>
|
||||
<class>google.registry.model.reporting.Spec11ThreatMatch</class>
|
||||
<class>google.registry.model.server.KmsSecretRevision</class>
|
||||
<class>google.registry.model.smd.SignedMarkRevocationList</class>
|
||||
<class>google.registry.model.tmch.ClaimsListShard</class>
|
||||
<class>google.registry.persistence.transaction.TransactionEntity</class>
|
||||
<class>google.registry.schema.cursor.Cursor</class>
|
||||
|
||||
@@ -28,6 +28,7 @@ public class DevTool {
|
||||
public static final ImmutableMap<String, Class<? extends Command>> COMMAND_MAP =
|
||||
ImmutableMap.of(
|
||||
"dump_golden_schema", DumpGoldenSchemaCommand.class,
|
||||
"generate_sql_er_diagram", GenerateSqlErDiagramCommand.class,
|
||||
"generate_sql_schema", GenerateSqlSchemaCommand.class);
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
// Copyright 2020 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.tools;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static google.registry.tools.GenerateSqlErDiagramCommand.DiagramType.ALL;
|
||||
import static google.registry.tools.GenerateSqlErDiagramCommand.DiagramType.BRIEF;
|
||||
import static google.registry.tools.GenerateSqlErDiagramCommand.DiagramType.FULL;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import com.beust.jcommander.converters.PathConverter;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.io.Resources;
|
||||
import google.registry.persistence.NomulusPostgreSql;
|
||||
import google.registry.util.ResourceUtils;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Properties;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import schemacrawler.schemacrawler.LoadOptionsBuilder;
|
||||
import schemacrawler.schemacrawler.SchemaCrawlerOptions;
|
||||
import schemacrawler.schemacrawler.SchemaCrawlerOptionsBuilder;
|
||||
import schemacrawler.schemacrawler.SchemaInfoLevelBuilder;
|
||||
import schemacrawler.tools.executable.SchemaCrawlerExecutable;
|
||||
import schemacrawler.tools.integration.diagram.DiagramOutputFormat;
|
||||
import schemacrawler.tools.options.OutputOptions;
|
||||
import schemacrawler.tools.options.OutputOptionsBuilder;
|
||||
|
||||
/** Command to generate ER diagrams for SQL schema. */
|
||||
@Parameters(separators = " =", commandDescription = "Generate ER diagrams for SQL schmea.")
|
||||
public class GenerateSqlErDiagramCommand implements Command {
|
||||
|
||||
private static final String DB_NAME = "postgres";
|
||||
private static final String DB_USER = "username";
|
||||
private static final String DB_PASSWORD = "password";
|
||||
private static final String FULL_DIAGRAM_COMMAND = "schema";
|
||||
private static final String BRIEF_DIAGRAM_COMMAND = "brief";
|
||||
private static final String FULL_DIAGRAM_FILE_NAME = "full_er_diagram.html";
|
||||
private static final String BRIEF_DIAGRAM_FILE_NAME = "brief_er_diagram.html";
|
||||
private static final String NOMULUS_GOLDEN_SCHEMA = "sql/schema/nomulus.golden.sql";
|
||||
private static final String FLYWAY_FILE = "sql/flyway.txt";
|
||||
private static final String SVG_PAN_ZOOM_LIB = "google/registry/tools/svg-pan-zoom.min.js";
|
||||
|
||||
// The HTML element ID for the last flyway file name
|
||||
static final String FLYWAY_FILE_ELEMENT_ID = "lastFlywayFile";
|
||||
|
||||
@Parameter(
|
||||
names = {"-o", "--out_dir"},
|
||||
description = "Name of the output directory to store ER diagrams.",
|
||||
converter = PathConverter.class,
|
||||
required = true)
|
||||
private Path outDir;
|
||||
|
||||
@Parameter(
|
||||
names = "--diagram_type",
|
||||
description =
|
||||
"Type of the generated ER diagram, can be FULL, BRIEF and ALL (defaults to ALL).")
|
||||
private DiagramType diagramType = ALL;
|
||||
|
||||
/** The type of ER diagram. */
|
||||
public enum DiagramType {
|
||||
/** An HTML file that has an embedded ER diagram showing the full SQL schema. */
|
||||
FULL,
|
||||
|
||||
/**
|
||||
* An HTML file that has an embedded ER diagram showing only significant columns, such as
|
||||
* primary and foreign key columns, and columns that are part of unique indexes.
|
||||
*/
|
||||
BRIEF,
|
||||
|
||||
/** Generates all types of ER diagrams. */
|
||||
ALL
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
if (!outDir.toFile().exists()) {
|
||||
checkState(outDir.toFile().mkdirs(), "Failed to create directory %s", outDir);
|
||||
}
|
||||
|
||||
PostgreSQLContainer postgresContainer =
|
||||
new PostgreSQLContainer(NomulusPostgreSql.getDockerTag())
|
||||
.withDatabaseName(DB_NAME)
|
||||
.withUsername(DB_USER)
|
||||
.withPassword(DB_PASSWORD);
|
||||
postgresContainer.start();
|
||||
|
||||
try (Connection conn = getConnection(postgresContainer)) {
|
||||
initDb(conn);
|
||||
if (diagramType == ALL || diagramType == FULL) {
|
||||
improveDiagramHtml(generateErDiagram(conn, FULL_DIAGRAM_COMMAND, FULL_DIAGRAM_FILE_NAME));
|
||||
}
|
||||
if (diagramType == ALL || diagramType == BRIEF) {
|
||||
improveDiagramHtml(generateErDiagram(conn, BRIEF_DIAGRAM_COMMAND, BRIEF_DIAGRAM_FILE_NAME));
|
||||
}
|
||||
} finally {
|
||||
postgresContainer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
private void improveDiagramHtml(Path diagram) {
|
||||
try {
|
||||
Document doc = Jsoup.parse(diagram.toFile(), StandardCharsets.UTF_8.name());
|
||||
|
||||
// Add the last name of the flyway file to the HTML so we can have a test to verify that if
|
||||
// the generated diagram is up to date.
|
||||
doc.select("body > table > tbody")
|
||||
.first()
|
||||
.append(
|
||||
String.format(
|
||||
"<tr>"
|
||||
+ "<td class=\"property_name\">last flyway file</td>"
|
||||
+ "<td id=\""
|
||||
+ FLYWAY_FILE_ELEMENT_ID
|
||||
+ "\" class=\"property_value\">"
|
||||
+ getLastFlywayFileName()
|
||||
+ "</td>"
|
||||
+ "</tr>"));
|
||||
|
||||
// Add pan and zoom support for the embedded SVG in the HTML.
|
||||
StringBuilder svgPanZoomLib =
|
||||
new StringBuilder("<script>")
|
||||
.append(ResourceUtils.readResourceUtf8(Resources.getResource(SVG_PAN_ZOOM_LIB)))
|
||||
.append("</script>");
|
||||
doc.select("head").first().append(svgPanZoomLib.toString());
|
||||
doc.select("svg")
|
||||
.first()
|
||||
.attributes()
|
||||
.add("id", "erDiagram")
|
||||
.add("style", "overflow: hidden; width: 100%; height: 800px");
|
||||
doc.select("body")
|
||||
.first()
|
||||
.append(
|
||||
"<script>"
|
||||
+ "svgPanZoom('#erDiagram', {"
|
||||
+ " zoomEnabled: true,"
|
||||
+ " controlIconsEnabled: true,"
|
||||
+ " fit: true,"
|
||||
+ " center: true,"
|
||||
+ " minZoom: 0.1"
|
||||
+ "});"
|
||||
+ "</script>");
|
||||
|
||||
Files.write(
|
||||
diagram, doc.outerHtml().getBytes(StandardCharsets.UTF_8), StandardOpenOption.WRITE);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Path generateErDiagram(Connection connection, String command, String fileName) {
|
||||
Path outputFile = outDir.resolve(fileName);
|
||||
|
||||
LoadOptionsBuilder loadOptionsBuilder =
|
||||
LoadOptionsBuilder.builder().withSchemaInfoLevel(SchemaInfoLevelBuilder.standard());
|
||||
SchemaCrawlerOptions options =
|
||||
SchemaCrawlerOptionsBuilder.newSchemaCrawlerOptions()
|
||||
.withLoadOptions(loadOptionsBuilder.toOptions());
|
||||
OutputOptions outputOptions =
|
||||
OutputOptionsBuilder.newOutputOptions(DiagramOutputFormat.htmlx, outputFile);
|
||||
|
||||
SchemaCrawlerExecutable executable = new SchemaCrawlerExecutable(command);
|
||||
executable.setSchemaCrawlerOptions(options);
|
||||
executable.setOutputOptions(outputOptions);
|
||||
executable.setConnection(connection);
|
||||
try {
|
||||
executable.execute();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return outputFile;
|
||||
}
|
||||
|
||||
private static Connection getConnection(PostgreSQLContainer container) {
|
||||
Properties info = new Properties();
|
||||
info.put("user", container.getUsername());
|
||||
info.put("password", container.getPassword());
|
||||
try {
|
||||
return container.getJdbcDriverInstance().connect(container.getJdbcUrl(), info);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void initDb(Connection connection) {
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
statement.execute(
|
||||
ResourceUtils.readResourceUtf8(Resources.getResource(NOMULUS_GOLDEN_SCHEMA)));
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static String getLastFlywayFileName() {
|
||||
try {
|
||||
return Iterables.getLast(
|
||||
Resources.readLines(Resources.getResource(FLYWAY_FILE), StandardCharsets.UTF_8));
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
17
core/src/nonprod/resources/google/registry/tools/svg-pan-zoom.min.js
vendored
Normal file
17
core/src/nonprod/resources/google/registry/tools/svg-pan-zoom.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -480,8 +480,7 @@ public class ExpandRecurringBillingEventsActionTest
|
||||
.setSyntheticCreationTime(testTime)
|
||||
.build());
|
||||
}
|
||||
assertBillingEventsForResource(
|
||||
domain, Iterables.toArray(expectedEvents, BillingEvent.class));
|
||||
assertBillingEventsForResource(domain, Iterables.toArray(expectedEvents, BillingEvent.class));
|
||||
assertCursorAt(testTime);
|
||||
}
|
||||
|
||||
|
||||
@@ -143,6 +143,7 @@ public class TestPipelineExtension extends Pipeline
|
||||
// Null until the pipeline has been run
|
||||
@Nullable private List<TransformHierarchy.Node> runVisitedNodes;
|
||||
|
||||
@SuppressWarnings("UnnecessaryLambda") // Stay true to the original class.
|
||||
private final Predicate<Node> isPAssertNode =
|
||||
node ->
|
||||
node.getTransform() instanceof PAssert.GroupThenAssert
|
||||
|
||||
@@ -805,30 +805,35 @@ class EppLifecycleDomainTest extends EppTestCase {
|
||||
|
||||
// As the losing registrar, read the request poll message, and then ack it.
|
||||
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
|
||||
String messageId = "1-C-EXAMPLE-20-26-2001";
|
||||
assertThatCommand("poll.xml")
|
||||
.atTime("2001-01-01T00:01:00Z")
|
||||
.hasResponse("poll_response_domain_transfer_request.xml");
|
||||
assertThatCommand("poll_ack.xml", ImmutableMap.of("ID", "1-C-EXAMPLE-17-23-2001"))
|
||||
.hasResponse("poll_response_domain_transfer_request.xml", ImmutableMap.of("ID", messageId));
|
||||
assertThatCommand("poll_ack.xml", ImmutableMap.of("ID", messageId))
|
||||
.atTime("2001-01-01T00:01:00Z")
|
||||
.hasResponse("poll_ack_response_empty.xml");
|
||||
|
||||
// Five days in the future, expect a server approval poll message to the loser, and ack it.
|
||||
messageId = "1-C-EXAMPLE-20-25-2001";
|
||||
assertThatCommand("poll.xml")
|
||||
.atTime("2001-01-06T00:01:00Z")
|
||||
.hasResponse("poll_response_domain_transfer_server_approve_loser.xml");
|
||||
assertThatCommand("poll_ack.xml", ImmutableMap.of("ID", "1-C-EXAMPLE-17-22-2001"))
|
||||
.hasResponse(
|
||||
"poll_response_domain_transfer_server_approve_loser.xml",
|
||||
ImmutableMap.of("ID", messageId));
|
||||
assertThatCommand("poll_ack.xml", ImmutableMap.of("ID", messageId))
|
||||
.atTime("2001-01-06T00:01:00Z")
|
||||
.hasResponse("poll_ack_response_empty.xml");
|
||||
assertThatLogoutSucceeds();
|
||||
|
||||
// Also expect a server approval poll message to the winner, with the transfer request trid.
|
||||
messageId = "1-C-EXAMPLE-20-24-2001";
|
||||
assertThatLoginSucceeds("TheRegistrar", "password2");
|
||||
assertThatCommand("poll.xml")
|
||||
.atTime("2001-01-06T00:02:00Z")
|
||||
.hasResponse(
|
||||
"poll_response_domain_transfer_server_approve_winner.xml",
|
||||
ImmutableMap.of("SERVER_TRID", transferRequestTrid));
|
||||
assertThatCommand("poll_ack.xml", ImmutableMap.of("ID", "1-C-EXAMPLE-17-21-2001"))
|
||||
ImmutableMap.of("SERVER_TRID", transferRequestTrid, "ID", messageId));
|
||||
assertThatCommand("poll_ack.xml", ImmutableMap.of("ID", messageId))
|
||||
.atTime("2001-01-06T00:02:00Z")
|
||||
.hasResponse("poll_ack_response_empty.xml");
|
||||
assertThatLogoutSucceeds();
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.util;
|
||||
package google.registry.flows.certs;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.util.CertificateChecker.CertificateViolation.ALGORITHM_CONSTRAINED;
|
||||
import static google.registry.util.CertificateChecker.CertificateViolation.EXPIRED;
|
||||
import static google.registry.util.CertificateChecker.CertificateViolation.NOT_YET_VALID;
|
||||
import static google.registry.util.CertificateChecker.CertificateViolation.RSA_KEY_LENGTH_TOO_SHORT;
|
||||
import static google.registry.util.CertificateChecker.CertificateViolation.VALIDITY_LENGTH_TOO_LONG;
|
||||
import static google.registry.flows.certs.CertificateChecker.CertificateViolation.ALGORITHM_CONSTRAINED;
|
||||
import static google.registry.flows.certs.CertificateChecker.CertificateViolation.EXPIRED;
|
||||
import static google.registry.flows.certs.CertificateChecker.CertificateViolation.NOT_YET_VALID;
|
||||
import static google.registry.flows.certs.CertificateChecker.CertificateViolation.RSA_KEY_LENGTH_TOO_SHORT;
|
||||
import static google.registry.flows.certs.CertificateChecker.CertificateViolation.VALIDITY_LENGTH_TOO_LONG;
|
||||
import static google.registry.testing.CertificateSamples.SAMPLE_CERT;
|
||||
import static google.registry.testing.CertificateSamples.SAMPLE_CERT3;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.util.SelfSignedCaCertificate;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.X509Certificate;
|
||||
@@ -189,6 +193,24 @@ class CertificateCheckerTest {
|
||||
.containsExactly(ALGORITHM_CONSTRAINED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_checkCertificate_validCertificateString() throws Exception {
|
||||
fakeClock.setTo(DateTime.parse("2020-11-01T00:00:00Z"));
|
||||
assertThat(certificateChecker.checkCertificate(SAMPLE_CERT3)).isEmpty();
|
||||
assertThat(certificateChecker.checkCertificate(SAMPLE_CERT))
|
||||
.containsExactly(VALIDITY_LENGTH_TOO_LONG);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_checkCertificate_invalidCertificateString() throws Exception {
|
||||
fakeClock.setTo(DateTime.parse("2020-11-01T00:00:00Z"));
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> certificateChecker.checkCertificate("bad certificate string"));
|
||||
assertThat(thrown).hasMessageThat().isEqualTo("Unable to read given certificate.");
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_isNearingExpiration_yesItIs() throws Exception {
|
||||
fakeClock.setTo(DateTime.parse("2021-09-20T00:00:00Z"));
|
||||
@@ -32,9 +32,11 @@ import com.googlecode.objectify.annotation.Id;
|
||||
import google.registry.schema.replay.EntityTest.EntityForTesting;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.util.CidrAddressBlock;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Arrays;
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -320,4 +322,40 @@ public class ImmutableObjectTest {
|
||||
root.set = ImmutableSet.of(Key.create(persistResource(ValueObject.create(1, "foo"))));
|
||||
assertThat(root.toHydratedString()).contains("foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInsignificantFields() {
|
||||
HasInsignificantFields instance1 =
|
||||
HasInsignificantFields.create("significant", "insignificant");
|
||||
HasInsignificantFields instance2 = HasInsignificantFields.create("significant", "other");
|
||||
assertThat(instance1).isEqualTo(instance2);
|
||||
|
||||
// The hash code test test is implicit in "equals", it is added here just for clarity.
|
||||
assertThat(instance1.hashCode()).isEqualTo(instance2.hashCode());
|
||||
assertThat(instance1.toString()).matches(
|
||||
"(?s)HasInsignificantFields (.*): \\{\\s*significant=significant\\s*\\}\\s*");
|
||||
}
|
||||
|
||||
static class HasInsignificantFields extends ImmutableObject {
|
||||
String significant;
|
||||
String insignificant;
|
||||
|
||||
static HasInsignificantFields create(String significant, String insignificant) {
|
||||
HasInsignificantFields instance = new HasInsignificantFields();
|
||||
instance.significant = significant;
|
||||
instance.insignificant = insignificant;
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Field, Object> getSignificantFields() {
|
||||
Map<Field, Object> result = new LinkedHashMap();
|
||||
for (Map.Entry<Field, Object> entry : ModelUtils.getFieldValues(this).entrySet()) {
|
||||
if (!entry.getKey().getName().equals("insignificant")) {
|
||||
result.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,12 @@ package google.registry.model.billing;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.UNLIMITED_USE;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.persistence.transaction.TransactionManagerUtil.ofyTmOrDoNothing;
|
||||
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveDomain;
|
||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static google.registry.testing.SqlHelper.saveRegistrar;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
@@ -39,13 +40,17 @@ import google.registry.model.domain.rgp.GracePeriodStatus;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.domain.token.AllocationToken.TokenStatus;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.testing.DualDatabaseTest;
|
||||
import google.registry.testing.TestOfyAndSql;
|
||||
import google.registry.testing.TestOfyOnly;
|
||||
import google.registry.util.DateTimeUtils;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link BillingEvent}. */
|
||||
@DualDatabaseTest
|
||||
public class BillingEventTest extends EntityTestCase {
|
||||
private final DateTime now = DateTime.now(UTC);
|
||||
|
||||
@@ -67,16 +72,26 @@ public class BillingEventTest extends EntityTestCase {
|
||||
void setUp() {
|
||||
createTld("tld");
|
||||
domain = persistActiveDomain("foo.tld");
|
||||
historyEntry = persistResource(
|
||||
new HistoryEntry.Builder()
|
||||
.setParent(domain)
|
||||
.setModificationTime(now)
|
||||
.build());
|
||||
historyEntry2 = persistResource(
|
||||
new HistoryEntry.Builder()
|
||||
.setParent(domain)
|
||||
.setModificationTime(now.plusDays(1))
|
||||
.build());
|
||||
historyEntry =
|
||||
persistResource(
|
||||
new HistoryEntry.Builder()
|
||||
.setParent(domain)
|
||||
.setModificationTime(now)
|
||||
.setRequestedByRegistrar(false)
|
||||
.setType(HistoryEntry.Type.DOMAIN_CREATE)
|
||||
.setXmlBytes(new byte[0])
|
||||
.build()
|
||||
.toChildHistoryEntity());
|
||||
historyEntry2 =
|
||||
persistResource(
|
||||
new HistoryEntry.Builder()
|
||||
.setParent(domain)
|
||||
.setModificationTime(now.plusDays(1))
|
||||
.setRequestedByRegistrar(false)
|
||||
.setType(HistoryEntry.Type.DOMAIN_CREATE)
|
||||
.setXmlBytes(new byte[0])
|
||||
.build()
|
||||
.toChildHistoryEntity());
|
||||
|
||||
AllocationToken allocationToken =
|
||||
persistResource(
|
||||
@@ -149,74 +164,38 @@ public class BillingEventTest extends EntityTestCase {
|
||||
.setEventTime(now.plusDays(1))
|
||||
.setBillingTime(now.plusYears(1).plusDays(45))
|
||||
.setRecurringEventKey(recurring.createVKey())));
|
||||
modification = persistResource(commonInit(
|
||||
new BillingEvent.Modification.Builder()
|
||||
.setParent(historyEntry2)
|
||||
.setReason(Reason.CREATE)
|
||||
.setCost(Money.of(USD, 1))
|
||||
.setDescription("Something happened")
|
||||
.setEventTime(now.plusDays(1))
|
||||
.setEventKey(Key.create(oneTime))));
|
||||
modification =
|
||||
ofyTmOrDoNothing(
|
||||
() ->
|
||||
persistResource(
|
||||
commonInit(
|
||||
new BillingEvent.Modification.Builder()
|
||||
.setParent(historyEntry2)
|
||||
.setReason(Reason.CREATE)
|
||||
.setCost(Money.of(USD, 1))
|
||||
.setDescription("Something happened")
|
||||
.setEventTime(now.plusDays(1))
|
||||
.setEventKey(Key.create(oneTime)))));
|
||||
}
|
||||
|
||||
private <E extends BillingEvent, B extends BillingEvent.Builder<E, B>> E commonInit(B builder) {
|
||||
return builder
|
||||
.setClientId("a registrar")
|
||||
.setTargetId("foo.tld")
|
||||
.build();
|
||||
return builder.setClientId("TheRegistrar").setTargetId("foo.tld").build();
|
||||
}
|
||||
|
||||
private void saveNewBillingEvent(BillingEvent billingEvent) {
|
||||
jpaTm().transact(() -> jpaTm().insert(billingEvent));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCloudSqlPersistence_OneTime() {
|
||||
saveRegistrar("a registrar");
|
||||
saveNewBillingEvent(oneTime);
|
||||
|
||||
BillingEvent.OneTime persisted = jpaTm().transact(() -> jpaTm().load(oneTime.createVKey()));
|
||||
// TODO(b/168325240): Remove this fix after VKeyConverter generates symmetric key for
|
||||
// AllocationToken.
|
||||
BillingEvent.OneTime fixed =
|
||||
persisted.asBuilder().setAllocationToken(oneTime.getAllocationToken().get()).build();
|
||||
assertThat(fixed).isEqualTo(oneTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCloudSqlPersistence_Cancellation() {
|
||||
saveRegistrar("a registrar");
|
||||
saveNewBillingEvent(oneTime);
|
||||
saveNewBillingEvent(cancellationOneTime);
|
||||
|
||||
BillingEvent.Cancellation persisted =
|
||||
jpaTm().transact(() -> jpaTm().load(cancellationOneTime.createVKey()));
|
||||
// TODO(b/168537779): Remove this fix after VKey<OneTime> can be reconstructed correctly.
|
||||
BillingEvent.Cancellation fixed =
|
||||
persisted.asBuilder().setOneTimeEventKey(oneTime.createVKey()).build();
|
||||
assertThat(fixed).isEqualTo(cancellationOneTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCloudSqlPersistence_Recurring() {
|
||||
saveRegistrar("a registrar");
|
||||
saveNewBillingEvent(recurring);
|
||||
|
||||
BillingEvent.Recurring persisted = jpaTm().transact(() -> jpaTm().load(recurring.createVKey()));
|
||||
assertThat(persisted).isEqualTo(recurring);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testPersistence() {
|
||||
assertThat(ofy().load().entity(oneTime).now()).isEqualTo(oneTime);
|
||||
assertThat(ofy().load().entity(oneTimeSynthetic).now()).isEqualTo(oneTimeSynthetic);
|
||||
assertThat(ofy().load().entity(recurring).now()).isEqualTo(recurring);
|
||||
assertThat(ofy().load().entity(cancellationOneTime).now()).isEqualTo(cancellationOneTime);
|
||||
assertThat(ofy().load().entity(cancellationRecurring).now()).isEqualTo(cancellationRecurring);
|
||||
assertThat(ofy().load().entity(modification).now()).isEqualTo(modification);
|
||||
assertThat(transactIfJpaTm(() -> tm().load(oneTime))).isEqualTo(oneTime);
|
||||
assertThat(transactIfJpaTm(() -> tm().load(oneTimeSynthetic))).isEqualTo(oneTimeSynthetic);
|
||||
assertThat(transactIfJpaTm(() -> tm().load(recurring))).isEqualTo(recurring);
|
||||
assertThat(transactIfJpaTm(() -> tm().load(cancellationOneTime)))
|
||||
.isEqualTo(cancellationOneTime);
|
||||
assertThat(transactIfJpaTm(() -> tm().load(cancellationRecurring)))
|
||||
.isEqualTo(cancellationRecurring);
|
||||
|
||||
ofyTmOrDoNothing(() -> assertThat(tm().load(modification)).isEqualTo(modification));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyOnly
|
||||
void testParenting() {
|
||||
// Note that these are all tested separately because BillingEvent is an abstract base class that
|
||||
// lacks the @Entity annotation, and thus we cannot call .type(BillingEvent.class)
|
||||
@@ -238,19 +217,14 @@ public class BillingEventTest extends EntityTestCase {
|
||||
.containsExactly(modification);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testCancellationMatching() {
|
||||
Key<?> recurringKey =
|
||||
ofy()
|
||||
.load()
|
||||
.entity(oneTimeSynthetic)
|
||||
.now()
|
||||
.getCancellationMatchingBillingEvent()
|
||||
.getOfyKey();
|
||||
assertThat(ofy().load().key(recurringKey).now()).isEqualTo(recurring);
|
||||
VKey<?> recurringKey =
|
||||
transactIfJpaTm(() -> tm().load(oneTimeSynthetic).getCancellationMatchingBillingEvent());
|
||||
assertThat(transactIfJpaTm(() -> tm().load(recurringKey))).isEqualTo(recurring);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyOnly
|
||||
void testIndexing() throws Exception {
|
||||
verifyIndexing(
|
||||
oneTime,
|
||||
@@ -272,7 +246,7 @@ public class BillingEventTest extends EntityTestCase {
|
||||
verifyIndexing(modification, "clientId", "eventTime");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_syntheticFlagWithoutCreationTime() {
|
||||
IllegalStateException thrown =
|
||||
assertThrows(
|
||||
@@ -288,7 +262,7 @@ public class BillingEventTest extends EntityTestCase {
|
||||
.contains("Synthetic creation time must be set if and only if the SYNTHETIC flag is set.");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_syntheticCreationTimeWithoutFlag() {
|
||||
IllegalStateException thrown =
|
||||
assertThrows(
|
||||
@@ -299,7 +273,7 @@ public class BillingEventTest extends EntityTestCase {
|
||||
.contains("Synthetic creation time must be set if and only if the SYNTHETIC flag is set");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_syntheticFlagWithoutCancellationMatchingKey() {
|
||||
IllegalStateException thrown =
|
||||
assertThrows(
|
||||
@@ -317,7 +291,7 @@ public class BillingEventTest extends EntityTestCase {
|
||||
+ "if and only if the SYNTHETIC flag is set");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_cancellationMatchingKeyWithoutFlag() {
|
||||
IllegalStateException thrown =
|
||||
assertThrows(
|
||||
@@ -334,7 +308,7 @@ public class BillingEventTest extends EntityTestCase {
|
||||
+ "if and only if the SYNTHETIC flag is set");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_cancellation_forGracePeriod_withOneTime() {
|
||||
BillingEvent.Cancellation newCancellation =
|
||||
BillingEvent.Cancellation.forGracePeriod(
|
||||
@@ -343,10 +317,15 @@ public class BillingEventTest extends EntityTestCase {
|
||||
"foo.tld");
|
||||
// Set ID to be the same to ignore for the purposes of comparison.
|
||||
newCancellation = newCancellation.asBuilder().setId(cancellationOneTime.getId()).build();
|
||||
assertThat(newCancellation).isEqualTo(cancellationOneTime);
|
||||
|
||||
// TODO(b/168537779): Remove setRecurringEventKey after symmetric VKey can be reconstructed
|
||||
// correctly.
|
||||
assertThat(newCancellation)
|
||||
.isEqualTo(
|
||||
cancellationOneTime.asBuilder().setOneTimeEventKey(oneTime.createVKey()).build());
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_cancellation_forGracePeriod_withRecurring() {
|
||||
BillingEvent.Cancellation newCancellation =
|
||||
BillingEvent.Cancellation.forGracePeriod(
|
||||
@@ -354,16 +333,21 @@ public class BillingEventTest extends EntityTestCase {
|
||||
GracePeriodStatus.AUTO_RENEW,
|
||||
domain.getRepoId(),
|
||||
now.plusYears(1).plusDays(45),
|
||||
"a registrar",
|
||||
"TheRegistrar",
|
||||
recurring.createVKey()),
|
||||
historyEntry2,
|
||||
"foo.tld");
|
||||
// Set ID to be the same to ignore for the purposes of comparison.
|
||||
newCancellation = newCancellation.asBuilder().setId(cancellationRecurring.getId()).build();
|
||||
assertThat(newCancellation).isEqualTo(cancellationRecurring);
|
||||
|
||||
// TODO(b/168537779): Remove setRecurringEventKey after symmetric VKey can be reconstructed
|
||||
// correctly.
|
||||
assertThat(newCancellation)
|
||||
.isEqualTo(
|
||||
cancellationRecurring.asBuilder().setRecurringEventKey(recurring.createVKey()).build());
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_cancellation_forGracePeriodWithoutBillingEvent() {
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
@@ -380,7 +364,7 @@ public class BillingEventTest extends EntityTestCase {
|
||||
assertThat(thrown).hasMessageThat().contains("grace period without billing event");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_cancellationWithNoBillingEvent() {
|
||||
IllegalStateException thrown =
|
||||
assertThrows(
|
||||
@@ -394,7 +378,7 @@ public class BillingEventTest extends EntityTestCase {
|
||||
assertThat(thrown).hasMessageThat().contains("exactly one billing event");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_cancellationWithBothBillingEvents() {
|
||||
IllegalStateException thrown =
|
||||
assertThrows(
|
||||
@@ -408,7 +392,7 @@ public class BillingEventTest extends EntityTestCase {
|
||||
assertThat(thrown).hasMessageThat().contains("exactly one billing event");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testDeadCodeThatDeletedScrapCommandsReference() {
|
||||
assertThat(recurring.getParentKey()).isEqualTo(Key.create(historyEntry));
|
||||
new BillingEvent.OneTime.Builder().setParent(Key.create(historyEntry));
|
||||
|
||||
@@ -21,6 +21,7 @@ import static google.registry.testing.SqlHelper.assertThrowForeignKeyViolation;
|
||||
import static google.registry.testing.SqlHelper.saveRegistrar;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
@@ -42,12 +43,14 @@ import google.registry.model.host.HostResource;
|
||||
import google.registry.model.poll.PollMessage;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.transfer.ContactTransferData;
|
||||
import google.registry.model.transfer.DomainTransferData;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.persistence.transaction.JpaTestRules;
|
||||
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageExtension;
|
||||
import google.registry.testing.DatastoreEntityExtension;
|
||||
import google.registry.testing.FakeClock;
|
||||
import java.util.Arrays;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Order;
|
||||
@@ -75,6 +78,7 @@ public class DomainBaseSqlTest {
|
||||
private HostResource host;
|
||||
private ContactResource contact;
|
||||
private ContactResource contact2;
|
||||
private ImmutableSet<GracePeriod> gracePeriods;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
@@ -445,6 +449,7 @@ public class DomainBaseSqlTest {
|
||||
() -> {
|
||||
historyEntry =
|
||||
new DomainHistory.Builder()
|
||||
.setId(100L)
|
||||
.setType(HistoryEntry.Type.DOMAIN_CREATE)
|
||||
.setPeriod(Period.create(1, Period.Unit.YEARS))
|
||||
.setModificationTime(DateTime.now(UTC))
|
||||
@@ -458,6 +463,7 @@ public class DomainBaseSqlTest {
|
||||
.build();
|
||||
BillingEvent.Recurring billEvent =
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setId(200L)
|
||||
.setReason(Reason.RENEW)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setTargetId("example.com")
|
||||
@@ -470,16 +476,51 @@ public class DomainBaseSqlTest {
|
||||
.build();
|
||||
PollMessage.Autorenew autorenewPollMessage =
|
||||
new PollMessage.Autorenew.Builder()
|
||||
.setId(300L)
|
||||
.setClientId("registrar1")
|
||||
.setEventTime(DateTime.now(UTC).plusYears(1))
|
||||
.setParent(historyEntry)
|
||||
.build();
|
||||
PollMessage.OneTime deletePollMessage =
|
||||
new PollMessage.OneTime.Builder()
|
||||
.setId(400L)
|
||||
.setClientId("registrar1")
|
||||
.setEventTime(DateTime.now(UTC).plusYears(1))
|
||||
.setParent(historyEntry)
|
||||
.build();
|
||||
BillingEvent.OneTime oneTimeBillingEvent =
|
||||
new BillingEvent.OneTime.Builder()
|
||||
.setId(500L)
|
||||
// Use SERVER_STATUS so we don't have to add a period.
|
||||
.setReason(Reason.SERVER_STATUS)
|
||||
.setTargetId("example.com")
|
||||
.setClientId("registrar1")
|
||||
.setDomainRepoId("4-COM")
|
||||
.setBillingTime(DateTime.now(UTC))
|
||||
.setCost(Money.of(USD, 100))
|
||||
.setEventTime(DateTime.now(UTC).plusYears(1))
|
||||
.setParent(historyEntry)
|
||||
.build();
|
||||
DomainTransferData transferData =
|
||||
new DomainTransferData.Builder()
|
||||
.setServerApproveBillingEvent(oneTimeBillingEvent.createVKey())
|
||||
.setServerApproveAutorenewEvent(billEvent.createVKey())
|
||||
.setServerApproveAutorenewPollMessage(autorenewPollMessage.createVKey())
|
||||
.build();
|
||||
gracePeriods =
|
||||
ImmutableSet.of(
|
||||
GracePeriod.create(
|
||||
GracePeriodStatus.ADD,
|
||||
"4-COM",
|
||||
END_OF_TIME,
|
||||
"registrar1",
|
||||
oneTimeBillingEvent.createVKey()),
|
||||
GracePeriod.createForRecurring(
|
||||
GracePeriodStatus.AUTO_RENEW,
|
||||
"4-COM",
|
||||
END_OF_TIME,
|
||||
"registrar1",
|
||||
billEvent.createVKey()));
|
||||
|
||||
jpaTm().insert(contact);
|
||||
jpaTm().insert(contact2);
|
||||
@@ -490,12 +531,15 @@ public class DomainBaseSqlTest {
|
||||
.setAutorenewBillingEvent(billEvent.createVKey())
|
||||
.setAutorenewPollMessage(autorenewPollMessage.createVKey())
|
||||
.setDeletePollMessage(deletePollMessage.createVKey())
|
||||
.setTransferData(transferData)
|
||||
.setGracePeriods(gracePeriods)
|
||||
.build();
|
||||
historyEntry = historyEntry.asBuilder().setDomainContent(domain).build();
|
||||
jpaTm().insert(historyEntry);
|
||||
jpaTm().insert(autorenewPollMessage);
|
||||
jpaTm().insert(billEvent);
|
||||
jpaTm().insert(deletePollMessage);
|
||||
jpaTm().insert(oneTimeBillingEvent);
|
||||
jpaTm().insert(domain);
|
||||
});
|
||||
|
||||
@@ -516,6 +560,16 @@ public class DomainBaseSqlTest {
|
||||
.isEqualTo(domain.getAutorenewBillingEvent());
|
||||
assertThat(persistedHistoryEntry.getDomainContent().get().getDeletePollMessage())
|
||||
.isEqualTo(domain.getDeletePollMessage());
|
||||
DomainTransferData persistedTransferData =
|
||||
persistedHistoryEntry.getDomainContent().get().getTransferData();
|
||||
DomainTransferData originalTransferData = domain.getTransferData();
|
||||
assertThat(persistedTransferData.getServerApproveBillingEvent())
|
||||
.isEqualTo(originalTransferData.getServerApproveBillingEvent());
|
||||
assertThat(persistedTransferData.getServerApproveAutorenewEvent())
|
||||
.isEqualTo(originalTransferData.getServerApproveAutorenewEvent());
|
||||
assertThat(persistedTransferData.getServerApproveAutorenewPollMessage())
|
||||
.isEqualTo(originalTransferData.getServerApproveAutorenewPollMessage());
|
||||
assertThat(persisted.getGracePeriods()).isEqualTo(gracePeriods);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -525,6 +579,7 @@ public class DomainBaseSqlTest {
|
||||
() -> {
|
||||
historyEntry =
|
||||
new DomainHistory.Builder()
|
||||
.setId(100L)
|
||||
.setType(HistoryEntry.Type.DOMAIN_CREATE)
|
||||
.setPeriod(Period.create(1, Period.Unit.YEARS))
|
||||
.setModificationTime(DateTime.now(UTC))
|
||||
@@ -538,6 +593,7 @@ public class DomainBaseSqlTest {
|
||||
.build();
|
||||
BillingEvent.Recurring billEvent =
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setId(200L)
|
||||
.setReason(Reason.RENEW)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setTargetId("example.com")
|
||||
@@ -550,16 +606,56 @@ public class DomainBaseSqlTest {
|
||||
.build();
|
||||
PollMessage.Autorenew autorenewPollMessage =
|
||||
new PollMessage.Autorenew.Builder()
|
||||
.setId(300L)
|
||||
.setClientId("registrar1")
|
||||
.setEventTime(DateTime.now(UTC).plusYears(1))
|
||||
.setParent(historyEntry)
|
||||
.build();
|
||||
PollMessage.OneTime deletePollMessage =
|
||||
new PollMessage.OneTime.Builder()
|
||||
.setId(400L)
|
||||
.setClientId("registrar1")
|
||||
.setEventTime(DateTime.now(UTC).plusYears(1))
|
||||
.setParent(historyEntry)
|
||||
.build();
|
||||
BillingEvent.OneTime oneTimeBillingEvent =
|
||||
new BillingEvent.OneTime.Builder()
|
||||
.setId(500L)
|
||||
// Use SERVER_STATUS so we don't have to add a period.
|
||||
.setReason(Reason.SERVER_STATUS)
|
||||
.setTargetId("example.com")
|
||||
.setClientId("registrar1")
|
||||
.setDomainRepoId("4-COM")
|
||||
.setBillingTime(DateTime.now(UTC))
|
||||
.setCost(Money.of(USD, 100))
|
||||
.setEventTime(DateTime.now(UTC).plusYears(1))
|
||||
.setParent(historyEntry)
|
||||
.build();
|
||||
DomainTransferData transferData =
|
||||
new DomainTransferData.Builder()
|
||||
.setServerApproveBillingEvent(
|
||||
createLegacyVKey(BillingEvent.OneTime.class, oneTimeBillingEvent.getId()))
|
||||
.setServerApproveAutorenewEvent(
|
||||
createLegacyVKey(BillingEvent.Recurring.class, billEvent.getId()))
|
||||
.setServerApproveAutorenewPollMessage(
|
||||
createLegacyVKey(
|
||||
PollMessage.Autorenew.class, autorenewPollMessage.getId()))
|
||||
.build();
|
||||
gracePeriods =
|
||||
ImmutableSet.of(
|
||||
GracePeriod.create(
|
||||
GracePeriodStatus.ADD,
|
||||
"4-COM",
|
||||
END_OF_TIME,
|
||||
"registrar1",
|
||||
createLegacyVKey(
|
||||
BillingEvent.OneTime.class, oneTimeBillingEvent.getId())),
|
||||
GracePeriod.createForRecurring(
|
||||
GracePeriodStatus.AUTO_RENEW,
|
||||
"4-COM",
|
||||
END_OF_TIME,
|
||||
"registrar1",
|
||||
createLegacyVKey(BillingEvent.Recurring.class, billEvent.getId())));
|
||||
|
||||
jpaTm().insert(contact);
|
||||
jpaTm().insert(contact2);
|
||||
@@ -570,15 +666,19 @@ public class DomainBaseSqlTest {
|
||||
.setAutorenewBillingEvent(
|
||||
createLegacyVKey(BillingEvent.Recurring.class, billEvent.getId()))
|
||||
.setAutorenewPollMessage(
|
||||
createLegacyVKey(PollMessage.Autorenew.class, deletePollMessage.getId()))
|
||||
createLegacyVKey(
|
||||
PollMessage.Autorenew.class, autorenewPollMessage.getId()))
|
||||
.setDeletePollMessage(
|
||||
createLegacyVKey(PollMessage.OneTime.class, autorenewPollMessage.getId()))
|
||||
createLegacyVKey(PollMessage.OneTime.class, deletePollMessage.getId()))
|
||||
.setTransferData(transferData)
|
||||
.setGracePeriods(gracePeriods)
|
||||
.build();
|
||||
historyEntry = historyEntry.asBuilder().setDomainContent(domain).build();
|
||||
jpaTm().insert(historyEntry);
|
||||
jpaTm().insert(autorenewPollMessage);
|
||||
jpaTm().insert(billEvent);
|
||||
jpaTm().insert(deletePollMessage);
|
||||
jpaTm().insert(oneTimeBillingEvent);
|
||||
jpaTm().insert(domain);
|
||||
});
|
||||
|
||||
@@ -599,6 +699,16 @@ public class DomainBaseSqlTest {
|
||||
.isEqualTo(domain.getAutorenewBillingEvent());
|
||||
assertThat(persistedHistoryEntry.getDomainContent().get().getDeletePollMessage())
|
||||
.isEqualTo(domain.getDeletePollMessage());
|
||||
DomainTransferData persistedTransferData =
|
||||
persistedHistoryEntry.getDomainContent().get().getTransferData();
|
||||
DomainTransferData originalTransferData = domain.getTransferData();
|
||||
assertThat(persistedTransferData.getServerApproveBillingEvent())
|
||||
.isEqualTo(originalTransferData.getServerApproveBillingEvent());
|
||||
assertThat(persistedTransferData.getServerApproveAutorenewEvent())
|
||||
.isEqualTo(originalTransferData.getServerApproveAutorenewEvent());
|
||||
assertThat(persistedTransferData.getServerApproveAutorenewPollMessage())
|
||||
.isEqualTo(originalTransferData.getServerApproveAutorenewPollMessage());
|
||||
assertThat(domain.getGracePeriods()).isEqualTo(gracePeriods);
|
||||
}
|
||||
|
||||
private <T> VKey<T> createLegacyVKey(Class<T> clazz, long id) {
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.google.common.collect.Ordering;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.model.EntityTestCase;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingEvent.Reason;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
@@ -67,6 +68,7 @@ public class DomainBaseTest extends EntityTestCase {
|
||||
private DomainBase domain;
|
||||
private VKey<BillingEvent.OneTime> oneTimeBillKey;
|
||||
private VKey<BillingEvent.Recurring> recurringBillKey;
|
||||
private Key<HistoryEntry> historyEntryKey;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
@@ -94,7 +96,7 @@ public class DomainBaseTest extends EntityTestCase {
|
||||
.setRepoId("3-COM")
|
||||
.build())
|
||||
.createVKey();
|
||||
Key<HistoryEntry> historyEntryKey =
|
||||
historyEntryKey =
|
||||
Key.create(
|
||||
persistResource(new HistoryEntry.Builder().setParent(domainKey.getOfyKey()).build()));
|
||||
oneTimeBillKey = VKey.from(Key.create(historyEntryKey, BillingEvent.OneTime.class, 1));
|
||||
@@ -164,10 +166,26 @@ public class DomainBaseTest extends EntityTestCase {
|
||||
|
||||
@Test
|
||||
void testPersistence() {
|
||||
// Note that this only verifies that the value stored under the foreign key is the same as that
|
||||
// stored under the primary key ("domain" is the domain loaded from the datastore, not the
|
||||
// original domain object).
|
||||
assertThat(loadByForeignKey(DomainBase.class, domain.getForeignKey(), fakeClock.nowUtc()))
|
||||
.hasValue(domain);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testVKeyRestoration() {
|
||||
assertThat(domain.deletePollMessageHistoryId).isEqualTo(historyEntryKey.getId());
|
||||
assertThat(domain.autorenewBillingEventHistoryId).isEqualTo(historyEntryKey.getId());
|
||||
assertThat(domain.autorenewPollMessageHistoryId).isEqualTo(historyEntryKey.getId());
|
||||
assertThat(domain.getTransferData().getServerApproveBillingEventHistoryId())
|
||||
.isEqualTo(historyEntryKey.getId());
|
||||
assertThat(domain.getTransferData().getServerApproveAutorenewEventHistoryId())
|
||||
.isEqualTo(historyEntryKey.getId());
|
||||
assertThat(domain.getTransferData().getServerApproveAutorenewPollMessageHistoryId())
|
||||
.isEqualTo(historyEntryKey.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIndexing() throws Exception {
|
||||
verifyIndexing(
|
||||
@@ -813,4 +831,63 @@ public class DomainBaseTest extends EntityTestCase {
|
||||
assertThat(getOnlyElement(clone.getGracePeriods()).getType())
|
||||
.isEqualTo(GracePeriodStatus.TRANSFER);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHistoryIdRestoration() {
|
||||
// Verify that history ids for billing events are restored during load from datastore. History
|
||||
// ids are not used by business code or persisted in datastore, but only to reconstruct
|
||||
// objectify keys when loading from SQL.
|
||||
DateTime now = fakeClock.nowUtc();
|
||||
domain =
|
||||
persistResource(
|
||||
domain
|
||||
.asBuilder()
|
||||
.setRegistrationExpirationTime(now.plusYears(1))
|
||||
.setGracePeriods(
|
||||
ImmutableSet.of(
|
||||
GracePeriod.createForRecurring(
|
||||
GracePeriodStatus.AUTO_RENEW,
|
||||
domain.getRepoId(),
|
||||
now.plusDays(1),
|
||||
"NewRegistrar",
|
||||
recurringBillKey),
|
||||
GracePeriod.create(
|
||||
GracePeriodStatus.RENEW,
|
||||
domain.getRepoId(),
|
||||
now.plusDays(1),
|
||||
"NewRegistrar",
|
||||
oneTimeBillKey)))
|
||||
.build());
|
||||
ImmutableSet<BillEventInfo> historyIds =
|
||||
domain.getGracePeriods().stream()
|
||||
.map(
|
||||
gp ->
|
||||
new BillEventInfo(
|
||||
gp.getRecurringBillingEvent(), gp.billingEventRecurringHistoryId,
|
||||
gp.getOneTimeBillingEvent(), gp.billingEventOneTimeHistoryId))
|
||||
.collect(toImmutableSet());
|
||||
assertThat(historyIds)
|
||||
.isEqualTo(
|
||||
ImmutableSet.of(
|
||||
new BillEventInfo(null, null, oneTimeBillKey, historyEntryKey.getId()),
|
||||
new BillEventInfo(recurringBillKey, historyEntryKey.getId(), null, null)));
|
||||
}
|
||||
|
||||
static class BillEventInfo extends ImmutableObject {
|
||||
VKey<BillingEvent.Recurring> billingEventRecurring;
|
||||
Long billingEventRecurringHistoryId;
|
||||
VKey<BillingEvent.OneTime> billingEventOneTime;
|
||||
Long billingEventOneTimeHistoryId;
|
||||
|
||||
BillEventInfo(
|
||||
VKey<BillingEvent.Recurring> billingEventRecurring,
|
||||
Long billingEventRecurringHistoryId,
|
||||
VKey<BillingEvent.OneTime> billingEventOneTime,
|
||||
Long billingEventOneTimeHistoryId) {
|
||||
this.billingEventRecurring = billingEventRecurring;
|
||||
this.billingEventRecurringHistoryId = billingEventRecurringHistoryId;
|
||||
this.billingEventOneTime = billingEventOneTime;
|
||||
this.billingEventOneTimeHistoryId = billingEventOneTimeHistoryId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ public class GracePeriodTest {
|
||||
|
||||
private final DateTime now = DateTime.now(UTC);
|
||||
private BillingEvent.OneTime onetime;
|
||||
private VKey<BillingEvent.Recurring> recurringKey;
|
||||
|
||||
@BeforeEach
|
||||
void before() {
|
||||
@@ -59,6 +60,14 @@ public class GracePeriodTest {
|
||||
.setPeriodYears(1)
|
||||
.setTargetId("foo.google")
|
||||
.build();
|
||||
recurringKey =
|
||||
VKey.create(
|
||||
Recurring.class,
|
||||
12345,
|
||||
Key.create(
|
||||
Key.create(Key.create(DomainBase.class, "1-TEST"), HistoryEntry.class, 343L),
|
||||
Recurring.class,
|
||||
12345));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -71,6 +80,24 @@ public class GracePeriodTest {
|
||||
assertThat(gracePeriod.getClientId()).isEqualTo("TheRegistrar");
|
||||
assertThat(gracePeriod.getExpirationTime()).isEqualTo(now.plusDays(1));
|
||||
assertThat(gracePeriod.hasBillingEvent()).isTrue();
|
||||
assertThat(gracePeriod.billingEventOneTimeHistoryId).isEqualTo(12345L);
|
||||
assertThat(gracePeriod.billingEventRecurringHistoryId).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_forRecurringEvent() {
|
||||
GracePeriod gracePeriod =
|
||||
GracePeriod.createForRecurring(
|
||||
GracePeriodStatus.AUTO_RENEW, "1-TEST", now.plusDays(1), "TheRegistrar", recurringKey);
|
||||
assertThat(gracePeriod.getType()).isEqualTo(GracePeriodStatus.AUTO_RENEW);
|
||||
assertThat(gracePeriod.getDomainRepoId()).isEqualTo("1-TEST");
|
||||
assertThat(gracePeriod.getOneTimeBillingEvent()).isNull();
|
||||
assertThat(gracePeriod.getRecurringBillingEvent()).isEqualTo(recurringKey);
|
||||
assertThat(gracePeriod.getClientId()).isEqualTo("TheRegistrar");
|
||||
assertThat(gracePeriod.getExpirationTime()).isEqualTo(now.plusDays(1));
|
||||
assertThat(gracePeriod.hasBillingEvent()).isTrue();
|
||||
assertThat(gracePeriod.billingEventOneTimeHistoryId).isNull();
|
||||
assertThat(gracePeriod.billingEventRecurringHistoryId).isEqualTo(343L);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -98,11 +125,6 @@ public class GracePeriodTest {
|
||||
|
||||
@Test
|
||||
void testFailure_createForRecurring_notAutoRenew() {
|
||||
Key<Recurring> recurringKey =
|
||||
Key.create(
|
||||
Key.create(Key.create(DomainBase.class, "1-TEST"), HistoryEntry.class, 343L),
|
||||
Recurring.class,
|
||||
12345);
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
@@ -112,7 +134,7 @@ public class GracePeriodTest {
|
||||
"1-TEST",
|
||||
now.plusDays(1),
|
||||
"TheRegistrar",
|
||||
VKey.create(Recurring.class, 12345, recurringKey)));
|
||||
recurringKey));
|
||||
assertThat(thrown).hasMessageThat().contains("autorenew");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.domain.DomainContent;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.domain.Period;
|
||||
import google.registry.model.domain.secdns.DelegationSignerData;
|
||||
import google.registry.model.eppcommon.Trid;
|
||||
import google.registry.model.host.HostResource;
|
||||
import google.registry.model.reporting.DomainTransactionRecord;
|
||||
@@ -141,6 +142,7 @@ public class DomainHistoryTest extends EntityTestCase {
|
||||
newDomainBase("example.tld", "domainRepoId", contact)
|
||||
.asBuilder()
|
||||
.setNameservers(host.createVKey())
|
||||
.setDsData(ImmutableSet.of(DelegationSignerData.create(1, 2, 3, new byte[] {0, 1, 2})))
|
||||
.build();
|
||||
jpaTm().transact(() -> jpaTm().insert(domain));
|
||||
return domain;
|
||||
|
||||
@@ -116,7 +116,8 @@ public class LegacyHistoryObjectTest extends EntityTestCase {
|
||||
// The objects will be mostly the same, but the DomainHistory object has a couple extra fields
|
||||
assertAboutImmutableObjects()
|
||||
.that(legacyHistoryEntry)
|
||||
.isEqualExceptFields(fromObjectify, "domainContent", "domainRepoId", "nsHosts");
|
||||
.isEqualExceptFields(
|
||||
fromObjectify, "domainContent", "domainRepoId", "nsHosts", "dsDataHistories");
|
||||
assertThat(fromObjectify instanceof DomainHistory).isTrue();
|
||||
DomainHistory legacyDomainHistory = (DomainHistory) fromObjectify;
|
||||
|
||||
@@ -129,7 +130,12 @@ public class LegacyHistoryObjectTest extends EntityTestCase {
|
||||
.that(legacyDomainHistory)
|
||||
.isEqualExceptFields(
|
||||
// NB: period, transaction records, and other client ID are added in #794
|
||||
legacyHistoryFromSql, "period", "domainTransactionRecords", "otherClientId", "nsHosts");
|
||||
legacyHistoryFromSql,
|
||||
"period",
|
||||
"domainTransactionRecords",
|
||||
"otherClientId",
|
||||
"nsHosts",
|
||||
"dsDataHistories");
|
||||
assertThat(nullToEmpty(legacyDomainHistory.getNsHosts()))
|
||||
.isEqualTo(nullToEmpty(legacyHistoryFromSql.getNsHosts()));
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import static google.registry.testing.DatastoreHelper.persistActiveContact;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
@@ -225,7 +224,7 @@ public class OfyTest {
|
||||
if (firstAttemptTime == null) {
|
||||
// Sleep a bit to ensure that the next attempt is at a new millisecond.
|
||||
firstAttemptTime = tm().getTransactionTime();
|
||||
sleepUninterruptibly(10, MILLISECONDS);
|
||||
sleepUninterruptibly(java.time.Duration.ofMillis(10));
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
assertThat(tm().getTransactionTime()).isGreaterThan(firstAttemptTime);
|
||||
|
||||
@@ -15,118 +15,116 @@
|
||||
package google.registry.model.rde;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.model.rde.RdeMode.FULL;
|
||||
import static google.registry.model.rde.RdeRevision.getNextRevision;
|
||||
import static google.registry.model.rde.RdeRevision.saveRevision;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.google.common.base.VerifyException;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.model.EntityTestCase;
|
||||
import google.registry.testing.DualDatabaseTest;
|
||||
import google.registry.testing.TestOfyAndSql;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
||||
/** Unit tests for {@link RdeRevision}. */
|
||||
public class RdeRevisionTest {
|
||||
@DualDatabaseTest
|
||||
public class RdeRevisionTest extends EntityTestCase {
|
||||
|
||||
@RegisterExtension
|
||||
final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withDatastoreAndCloudSql().build();
|
||||
public RdeRevisionTest() {
|
||||
super(JpaEntityCoverageCheck.ENABLED);
|
||||
}
|
||||
|
||||
@Test
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
fakeClock.setTo(DateTime.parse("1984-12-18TZ"));
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testGetNextRevision_objectDoesntExist_returnsZero() {
|
||||
assertThat(getNextRevision("torment", DateTime.parse("1984-12-18TZ"), FULL)).isEqualTo(0);
|
||||
tm().transact(
|
||||
() -> assertThat(getNextRevision("torment", fakeClock.nowUtc(), FULL)).isEqualTo(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testGetNextRevision_objectExistsAtZero_returnsOne() {
|
||||
save("sorrow", DateTime.parse("1984-12-18TZ"), FULL, 0);
|
||||
assertThat(getNextRevision("sorrow", DateTime.parse("1984-12-18TZ"), FULL)).isEqualTo(1);
|
||||
save("sorrow", fakeClock.nowUtc(), FULL, 0);
|
||||
tm().transact(
|
||||
() -> assertThat(getNextRevision("sorrow", fakeClock.nowUtc(), FULL)).isEqualTo(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSaveRevision_objectDoesntExist_newRevisionIsZero_nextRevIsOne() {
|
||||
tm().transact(() -> saveRevision("despondency", DateTime.parse("1984-12-18TZ"), FULL, 0));
|
||||
tm().transact(() -> saveRevision("despondency", fakeClock.nowUtc(), FULL, 0));
|
||||
tm().transact(
|
||||
() ->
|
||||
assertThat(getNextRevision("despondency", DateTime.parse("1984-12-18TZ"), FULL))
|
||||
.isEqualTo(1));
|
||||
assertThat(getNextRevision("despondency", fakeClock.nowUtc(), FULL)).isEqualTo(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSaveRevision_objectDoesntExist_newRevisionIsOne_throwsVe() {
|
||||
VerifyException thrown =
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
VerifyException.class,
|
||||
() ->
|
||||
tm().transact(
|
||||
() ->
|
||||
saveRevision("despondency", DateTime.parse("1984-12-18TZ"), FULL, 1)));
|
||||
assertThat(thrown).hasMessageThat().contains("object missing");
|
||||
IllegalArgumentException.class,
|
||||
() -> tm().transact(() -> saveRevision("despondency", fakeClock.nowUtc(), FULL, 1)));
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.isEqualTo(
|
||||
"Couldn't find existing RDE revision despondency_1984-12-18_full "
|
||||
+ "when trying to save new revision 1");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSaveRevision_objectExistsAtZero_newRevisionIsZero_throwsVe() {
|
||||
save("melancholy", DateTime.parse("1984-12-18TZ"), FULL, 0);
|
||||
VerifyException thrown =
|
||||
save("melancholy", fakeClock.nowUtc(), FULL, 0);
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
VerifyException.class,
|
||||
() ->
|
||||
tm().transact(
|
||||
() -> saveRevision("melancholy", DateTime.parse("1984-12-18TZ"), FULL, 0)));
|
||||
IllegalArgumentException.class,
|
||||
() -> tm().transact(() -> saveRevision("melancholy", fakeClock.nowUtc(), FULL, 0)));
|
||||
assertThat(thrown).hasMessageThat().contains("object already created");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSaveRevision_objectExistsAtZero_newRevisionIsOne_nextRevIsTwo() {
|
||||
save("melancholy", DateTime.parse("1984-12-18TZ"), FULL, 0);
|
||||
tm().transact(() -> saveRevision("melancholy", DateTime.parse("1984-12-18TZ"), FULL, 1));
|
||||
tm().transact(
|
||||
() ->
|
||||
assertThat(getNextRevision("melancholy", DateTime.parse("1984-12-18TZ"), FULL))
|
||||
.isEqualTo(2));
|
||||
DateTime startOfDay = fakeClock.nowUtc().withTimeAtStartOfDay();
|
||||
save("melancholy", startOfDay, FULL, 0);
|
||||
fakeClock.advanceOneMilli();
|
||||
tm().transact(() -> saveRevision("melancholy", startOfDay, FULL, 1));
|
||||
tm().transact(() -> assertThat(getNextRevision("melancholy", startOfDay, FULL)).isEqualTo(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSaveRevision_objectExistsAtZero_newRevisionIsTwo_throwsVe() {
|
||||
save("melancholy", DateTime.parse("1984-12-18TZ"), FULL, 0);
|
||||
VerifyException thrown =
|
||||
save("melancholy", fakeClock.nowUtc(), FULL, 0);
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
VerifyException.class,
|
||||
() ->
|
||||
tm().transact(
|
||||
() -> saveRevision("melancholy", DateTime.parse("1984-12-18TZ"), FULL, 2)));
|
||||
assertThat(thrown).hasMessageThat().contains("should be at 1 ");
|
||||
IllegalArgumentException.class,
|
||||
() -> tm().transact(() -> saveRevision("melancholy", fakeClock.nowUtc(), FULL, 2)));
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.contains("RDE revision object should be at revision 1 but was");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSaveRevision_negativeRevision_throwsIae() {
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
tm().transact(
|
||||
() ->
|
||||
saveRevision("melancholy", DateTime.parse("1984-12-18TZ"), FULL, -1)));
|
||||
() -> tm().transact(() -> saveRevision("melancholy", fakeClock.nowUtc(), FULL, -1)));
|
||||
assertThat(thrown).hasMessageThat().contains("Negative revision");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSaveRevision_callerNotInTransaction_throwsIse() {
|
||||
IllegalStateException thrown =
|
||||
assertThrows(
|
||||
IllegalStateException.class,
|
||||
() -> saveRevision("frenzy", DateTime.parse("1984-12-18TZ"), FULL, 1));
|
||||
IllegalStateException.class, () -> saveRevision("frenzy", fakeClock.nowUtc(), FULL, 1));
|
||||
assertThat(thrown).hasMessageThat().contains("transaction");
|
||||
}
|
||||
|
||||
public static void save(String tld, DateTime date, RdeMode mode, int revision) {
|
||||
String triplet = RdeNamingUtils.makePartialName(tld, date, mode);
|
||||
RdeRevision object = new RdeRevision();
|
||||
object.id = triplet;
|
||||
object.revision = revision;
|
||||
ofy().saveWithoutBackup().entity(object).now();
|
||||
RdeRevision object = RdeRevision.create(triplet, tld, date.toLocalDate(), mode, revision);
|
||||
tm().transact(() -> tm().put(object));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,15 +92,13 @@ public class Spec11ThreatMatchDaoTest extends EntityTestCase {
|
||||
}
|
||||
|
||||
private Spec11ThreatMatch createThreatMatch(String domainName, LocalDate date) {
|
||||
Spec11ThreatMatch threatMatch =
|
||||
new Spec11ThreatMatch()
|
||||
.asBuilder()
|
||||
.setThreatTypes(ImmutableSet.of(ThreatType.MALWARE))
|
||||
.setCheckDate(date)
|
||||
.setDomainName(domainName)
|
||||
.setRegistrarId("Example Registrar")
|
||||
.setDomainRepoId("1-COM")
|
||||
.build();
|
||||
return threatMatch;
|
||||
return new Spec11ThreatMatch()
|
||||
.asBuilder()
|
||||
.setThreatTypes(ImmutableSet.of(ThreatType.MALWARE))
|
||||
.setCheckDate(date)
|
||||
.setDomainName(domainName)
|
||||
.setRegistrarId("Example Registrar")
|
||||
.setDomainRepoId("1-COM")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright 2020 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.model.server;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
import google.registry.persistence.transaction.JpaTestRules;
|
||||
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageExtension;
|
||||
import google.registry.testing.DatastoreEntityExtension;
|
||||
import google.registry.testing.FakeClock;
|
||||
import java.util.Optional;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Tests for {@link google.registry.model.server.KmsSecretRevisionSqlDao}. */
|
||||
public class KmsSecretRevisionSqlDaoTest {
|
||||
|
||||
private final FakeClock fakeClock = new FakeClock();
|
||||
|
||||
@RegisterExtension
|
||||
@Order(value = 1)
|
||||
DatastoreEntityExtension datastoreEntityExtension = new DatastoreEntityExtension();
|
||||
|
||||
@RegisterExtension
|
||||
JpaIntegrationWithCoverageExtension jpa =
|
||||
new JpaTestRules.Builder().withClock(fakeClock).buildIntegrationWithCoverageExtension();
|
||||
|
||||
@Test
|
||||
void testSaveAndRetrieve() {
|
||||
KmsSecretRevision revision = createRevision();
|
||||
jpaTm().transact(() -> KmsSecretRevisionSqlDao.save(revision));
|
||||
Optional<KmsSecretRevision> fromSql =
|
||||
jpaTm().transact(() -> KmsSecretRevisionSqlDao.getLatestRevision("secretName"));
|
||||
assertThat(fromSql.isPresent()).isTrue();
|
||||
assertAboutImmutableObjects().that(revision).isEqualExceptFields(fromSql.get(), "creationTime");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMultipleRevisions() {
|
||||
KmsSecretRevision revision = createRevision();
|
||||
jpaTm().transact(() -> KmsSecretRevisionSqlDao.save(revision));
|
||||
|
||||
KmsSecretRevision secondRevision = createRevision();
|
||||
secondRevision.encryptedValue = "someOtherValue";
|
||||
jpaTm().transact(() -> KmsSecretRevisionSqlDao.save(secondRevision));
|
||||
|
||||
Optional<KmsSecretRevision> fromSql =
|
||||
jpaTm().transact(() -> KmsSecretRevisionSqlDao.getLatestRevision("secretName"));
|
||||
assertThat(fromSql.isPresent()).isTrue();
|
||||
assertThat(fromSql.get().getEncryptedValue()).isEqualTo("someOtherValue");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNonexistent() {
|
||||
KmsSecretRevision revision = createRevision();
|
||||
jpaTm().transact(() -> KmsSecretRevisionSqlDao.save(revision));
|
||||
assertThat(
|
||||
jpaTm()
|
||||
.transact(() -> KmsSecretRevisionSqlDao.getLatestRevision("someOtherSecretName"))
|
||||
.isPresent())
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
private KmsSecretRevision createRevision() {
|
||||
return new KmsSecretRevision.Builder()
|
||||
.setEncryptedValue("encrypted")
|
||||
.setKmsCryptoKeyVersionName("version")
|
||||
.setParent("secretName")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
// Copyright 2020 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.model.smd;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.persistence.transaction.JpaTestRules;
|
||||
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageExtension;
|
||||
import google.registry.testing.DatastoreEntityExtension;
|
||||
import google.registry.testing.DualDatabaseTest;
|
||||
import google.registry.testing.FakeClock;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
@DualDatabaseTest
|
||||
public class SignedMarkRevocationListDaoTest {
|
||||
|
||||
private final FakeClock fakeClock = new FakeClock();
|
||||
|
||||
@RegisterExtension
|
||||
final JpaIntegrationWithCoverageExtension jpa =
|
||||
new JpaTestRules.Builder().withClock(fakeClock).buildIntegrationWithCoverageExtension();
|
||||
|
||||
@RegisterExtension
|
||||
@Order(value = 1)
|
||||
final DatastoreEntityExtension datastoreEntityExtension = new DatastoreEntityExtension();
|
||||
|
||||
@Test
|
||||
void testSave_success() {
|
||||
SignedMarkRevocationList list =
|
||||
SignedMarkRevocationList.create(
|
||||
fakeClock.nowUtc(), ImmutableMap.of("mark", fakeClock.nowUtc().minusHours(1)));
|
||||
SignedMarkRevocationListDao.trySave(list);
|
||||
SignedMarkRevocationList fromDb = SignedMarkRevocationListDao.getLatestRevision().get();
|
||||
assertAboutImmutableObjects().that(fromDb).isEqualExceptFields(list);
|
||||
}
|
||||
|
||||
@Test
|
||||
void trySave_failureIsSwallowed() {
|
||||
SignedMarkRevocationList list =
|
||||
SignedMarkRevocationList.create(
|
||||
fakeClock.nowUtc(), ImmutableMap.of("mark", fakeClock.nowUtc().minusHours(1)));
|
||||
SignedMarkRevocationListDao.trySave(list);
|
||||
SignedMarkRevocationList fromDb = SignedMarkRevocationListDao.getLatestRevision().get();
|
||||
assertAboutImmutableObjects().that(fromDb).isEqualExceptFields(list);
|
||||
|
||||
// This should throw an exception, which is swallowed and nothing changed
|
||||
SignedMarkRevocationListDao.trySave(list);
|
||||
SignedMarkRevocationList secondFromDb = SignedMarkRevocationListDao.getLatestRevision().get();
|
||||
assertAboutImmutableObjects().that(secondFromDb).isEqualExceptFields(fromDb);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRetrieval_notPresent() {
|
||||
assertThat(SignedMarkRevocationListDao.getLatestRevision().isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSaveAndRetrieval_emptyList() {
|
||||
SignedMarkRevocationList list =
|
||||
SignedMarkRevocationList.create(fakeClock.nowUtc(), ImmutableMap.of());
|
||||
SignedMarkRevocationListDao.trySave(list);
|
||||
SignedMarkRevocationList fromDb = SignedMarkRevocationListDao.getLatestRevision().get();
|
||||
assertAboutImmutableObjects().that(fromDb).isEqualExceptFields(list);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSave_multipleVersions() {
|
||||
SignedMarkRevocationList list =
|
||||
SignedMarkRevocationList.create(
|
||||
fakeClock.nowUtc(), ImmutableMap.of("mark", fakeClock.nowUtc().minusHours(1)));
|
||||
SignedMarkRevocationListDao.trySave(list);
|
||||
assertThat(
|
||||
SignedMarkRevocationListDao.getLatestRevision()
|
||||
.get()
|
||||
.isSmdRevoked("mark", fakeClock.nowUtc()))
|
||||
.isTrue();
|
||||
|
||||
// Now remove the revocation
|
||||
SignedMarkRevocationList secondList =
|
||||
SignedMarkRevocationList.create(fakeClock.nowUtc(), ImmutableMap.of());
|
||||
SignedMarkRevocationListDao.trySave(secondList);
|
||||
assertThat(
|
||||
SignedMarkRevocationListDao.getLatestRevision()
|
||||
.get()
|
||||
.isSmdRevoked("mark", fakeClock.nowUtc()))
|
||||
.isFalse();
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
package google.registry.model.smd;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.model.smd.SignedMarkRevocationList.SHARD_SIZE;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
@@ -72,10 +73,11 @@ public class SignedMarkRevocationListTest {
|
||||
revokes.put(Integer.toString(i), clock.nowUtc());
|
||||
}
|
||||
// Save it with sharding, and make sure that reloading it works.
|
||||
SignedMarkRevocationList unsharded = SignedMarkRevocationList
|
||||
.create(clock.nowUtc(), revokes.build())
|
||||
.save();
|
||||
assertThat(SignedMarkRevocationList.get()).isEqualTo(unsharded);
|
||||
SignedMarkRevocationList unsharded =
|
||||
SignedMarkRevocationList.create(clock.nowUtc(), revokes.build()).save();
|
||||
assertAboutImmutableObjects()
|
||||
.that(SignedMarkRevocationList.get())
|
||||
.isEqualExceptFields(unsharded, "revisionId");
|
||||
assertThat(ofy().load().type(SignedMarkRevocationList.class).count()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@@ -91,7 +93,9 @@ public class SignedMarkRevocationListTest {
|
||||
SignedMarkRevocationList unsharded = SignedMarkRevocationList
|
||||
.create(clock.nowUtc(), revokes.build())
|
||||
.save();
|
||||
assertThat(SignedMarkRevocationList.get()).isEqualTo(unsharded);
|
||||
assertAboutImmutableObjects()
|
||||
.that(SignedMarkRevocationList.get())
|
||||
.isEqualExceptFields(unsharded, "revisionId");
|
||||
assertThat(ofy().load().type(SignedMarkRevocationList.class).count()).isEqualTo(4);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.testing.DualDatabaseTest;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.InjectExtension;
|
||||
import google.registry.testing.TestOfyAndSql;
|
||||
import google.registry.testing.TestOfyOnly;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
@@ -40,7 +42,6 @@ import java.util.stream.Stream;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.TestTemplate;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/**
|
||||
@@ -78,28 +79,28 @@ public class TransactionManagerTest {
|
||||
fakeClock.advanceOneMilli();
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void inTransaction_returnsCorrespondingResult() {
|
||||
assertThat(tm().inTransaction()).isFalse();
|
||||
tm().transact(() -> assertThat(tm().inTransaction()).isTrue());
|
||||
assertThat(tm().inTransaction()).isFalse();
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void assertInTransaction_throwsExceptionWhenNotInTransaction() {
|
||||
assertThrows(IllegalStateException.class, () -> tm().assertInTransaction());
|
||||
tm().transact(() -> tm().assertInTransaction());
|
||||
assertThrows(IllegalStateException.class, () -> tm().assertInTransaction());
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void getTransactionTime_throwsExceptionWhenNotInTransaction() {
|
||||
assertThrows(IllegalStateException.class, () -> tm().getTransactionTime());
|
||||
tm().transact(() -> assertThat(tm().getTransactionTime()).isEqualTo(fakeClock.nowUtc()));
|
||||
assertThrows(IllegalStateException.class, () -> tm().getTransactionTime());
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void transact_hasNoEffectWithPartialSuccess() {
|
||||
assertEntityNotExist(theEntity);
|
||||
assertThrows(
|
||||
@@ -113,21 +114,21 @@ public class TransactionManagerTest {
|
||||
assertEntityNotExist(theEntity);
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void transact_reusesExistingTransaction() {
|
||||
assertEntityNotExist(theEntity);
|
||||
tm().transact(() -> tm().transact(() -> tm().insert(theEntity)));
|
||||
assertEntityExists(theEntity);
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void transactNew_succeeds() {
|
||||
assertEntityNotExist(theEntity);
|
||||
tm().transactNew(() -> tm().insert(theEntity));
|
||||
assertEntityExists(theEntity);
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void transactNewReadOnly_succeeds() {
|
||||
assertEntityNotExist(theEntity);
|
||||
tm().transact(() -> tm().insert(theEntity));
|
||||
@@ -136,7 +137,7 @@ public class TransactionManagerTest {
|
||||
assertThat(persisted).isEqualTo(theEntity);
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void transactNewReadOnly_throwsWhenWritingEntity() {
|
||||
assertEntityNotExist(theEntity);
|
||||
assertThrows(
|
||||
@@ -144,7 +145,7 @@ public class TransactionManagerTest {
|
||||
assertEntityNotExist(theEntity);
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void saveNew_succeeds() {
|
||||
assertEntityNotExist(theEntity);
|
||||
tm().transact(() -> tm().insert(theEntity));
|
||||
@@ -152,14 +153,14 @@ public class TransactionManagerTest {
|
||||
assertThat(tm().transact(() -> tm().load(theEntity.key()))).isEqualTo(theEntity);
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void saveAllNew_succeeds() {
|
||||
assertAllEntitiesNotExist(moreEntities);
|
||||
tm().transact(() -> tm().insertAll(moreEntities));
|
||||
assertAllEntitiesExist(moreEntities);
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void saveNewOrUpdate_persistsNewEntity() {
|
||||
assertEntityNotExist(theEntity);
|
||||
tm().transact(() -> tm().put(theEntity));
|
||||
@@ -167,7 +168,7 @@ public class TransactionManagerTest {
|
||||
assertThat(tm().transact(() -> tm().load(theEntity.key()))).isEqualTo(theEntity);
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void saveNewOrUpdate_updatesExistingEntity() {
|
||||
tm().transact(() -> tm().insert(theEntity));
|
||||
TestEntity persisted = tm().transact(() -> tm().load(theEntity.key()));
|
||||
@@ -179,14 +180,14 @@ public class TransactionManagerTest {
|
||||
assertThat(persisted.data).isEqualTo("bar");
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void saveNewOrUpdateAll_succeeds() {
|
||||
assertAllEntitiesNotExist(moreEntities);
|
||||
tm().transact(() -> tm().putAll(moreEntities));
|
||||
assertAllEntitiesExist(moreEntities);
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void update_succeeds() {
|
||||
tm().transact(() -> tm().insert(theEntity));
|
||||
TestEntity persisted =
|
||||
@@ -202,7 +203,7 @@ public class TransactionManagerTest {
|
||||
assertThat(persisted.data).isEqualTo("bar");
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void load_succeeds() {
|
||||
assertEntityNotExist(theEntity);
|
||||
tm().transact(() -> tm().insert(theEntity));
|
||||
@@ -211,14 +212,14 @@ public class TransactionManagerTest {
|
||||
assertThat(persisted.data).isEqualTo("foo");
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void load_throwsOnMissingElement() {
|
||||
assertEntityNotExist(theEntity);
|
||||
assertThrows(
|
||||
NoSuchElementException.class, () -> tm().transact(() -> tm().load(theEntity.key())));
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void maybeLoad_succeeds() {
|
||||
assertEntityNotExist(theEntity);
|
||||
tm().transact(() -> tm().insert(theEntity));
|
||||
@@ -227,13 +228,13 @@ public class TransactionManagerTest {
|
||||
assertThat(persisted.data).isEqualTo("foo");
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void maybeLoad_nonExistentObject() {
|
||||
assertEntityNotExist(theEntity);
|
||||
assertThat(tm().transact(() -> tm().maybeLoad(theEntity.key())).isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void delete_succeeds() {
|
||||
tm().transact(() -> tm().insert(theEntity));
|
||||
assertEntityExists(theEntity);
|
||||
@@ -242,14 +243,14 @@ public class TransactionManagerTest {
|
||||
assertEntityNotExist(theEntity);
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void delete_doNothingWhenEntityNotExist() {
|
||||
assertEntityNotExist(theEntity);
|
||||
tm().transact(() -> tm().delete(theEntity.key()));
|
||||
assertEntityNotExist(theEntity);
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void delete_succeedsForEntitySet() {
|
||||
assertAllEntitiesNotExist(moreEntities);
|
||||
tm().transact(() -> tm().insertAll(moreEntities));
|
||||
@@ -261,7 +262,7 @@ public class TransactionManagerTest {
|
||||
assertAllEntitiesNotExist(moreEntities);
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void delete_ignoreNonExistentEntity() {
|
||||
assertAllEntitiesNotExist(moreEntities);
|
||||
tm().transact(() -> tm().insertAll(moreEntities));
|
||||
@@ -276,7 +277,16 @@ public class TransactionManagerTest {
|
||||
assertAllEntitiesNotExist(moreEntities);
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void delete_deletesTheGivenEntity() {
|
||||
tm().transact(() -> tm().insert(theEntity));
|
||||
assertEntityExists(theEntity);
|
||||
fakeClock.advanceOneMilli();
|
||||
tm().transact(() -> tm().delete(theEntity));
|
||||
assertEntityNotExist(theEntity);
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void load_multi() {
|
||||
assertAllEntitiesNotExist(moreEntities);
|
||||
tm().transact(() -> tm().insertAll(moreEntities));
|
||||
@@ -286,7 +296,7 @@ public class TransactionManagerTest {
|
||||
.isEqualTo(Maps.uniqueIndex(moreEntities, TestEntity::key));
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void load_multiWithDuplicateKeys() {
|
||||
assertAllEntitiesNotExist(moreEntities);
|
||||
tm().transact(() -> tm().insertAll(moreEntities));
|
||||
@@ -298,7 +308,7 @@ public class TransactionManagerTest {
|
||||
.isEqualTo(Maps.uniqueIndex(moreEntities, TestEntity::key));
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@TestOfyAndSql
|
||||
void load_multiMissingKeys() {
|
||||
assertAllEntitiesNotExist(moreEntities);
|
||||
tm().transact(() -> tm().insertAll(moreEntities));
|
||||
@@ -310,6 +320,14 @@ public class TransactionManagerTest {
|
||||
.isEqualTo(Maps.uniqueIndex(moreEntities, TestEntity::key));
|
||||
}
|
||||
|
||||
@TestOfyOnly
|
||||
void loadAllForOfyTm_throwsExceptionInTransaction() {
|
||||
assertAllEntitiesNotExist(moreEntities);
|
||||
tm().transact(() -> tm().insertAll(moreEntities));
|
||||
assertThrows(
|
||||
IllegalArgumentException.class, () -> tm().transact(() -> tm().loadAll(TestEntity.class)));
|
||||
}
|
||||
|
||||
private static void assertEntityExists(TestEntity entity) {
|
||||
assertThat(tm().transact(() -> tm().exists(entity))).isTrue();
|
||||
}
|
||||
|
||||
@@ -24,10 +24,13 @@ import google.registry.model.history.ContactHistoryTest;
|
||||
import google.registry.model.history.DomainHistoryTest;
|
||||
import google.registry.model.history.HostHistoryTest;
|
||||
import google.registry.model.poll.PollMessageTest;
|
||||
import google.registry.model.rde.RdeRevisionTest;
|
||||
import google.registry.model.registry.RegistryLockDaoTest;
|
||||
import google.registry.model.registry.RegistryTest;
|
||||
import google.registry.model.registry.label.ReservedListSqlDaoTest;
|
||||
import google.registry.model.reporting.Spec11ThreatMatchTest;
|
||||
import google.registry.model.server.KmsSecretRevisionSqlDaoTest;
|
||||
import google.registry.model.smd.SignedMarkRevocationListDaoTest;
|
||||
import google.registry.model.tmch.ClaimsListDaoTest;
|
||||
import google.registry.persistence.transaction.JpaEntityCoverageExtension;
|
||||
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageExtension;
|
||||
@@ -83,13 +86,16 @@ import org.junit.runner.RunWith;
|
||||
DomainBaseSqlTest.class,
|
||||
DomainHistoryTest.class,
|
||||
HostHistoryTest.class,
|
||||
KmsSecretRevisionSqlDaoTest.class,
|
||||
LockDaoTest.class,
|
||||
PollMessageTest.class,
|
||||
PremiumListDaoTest.class,
|
||||
RdeRevisionTest.class,
|
||||
RegistrarDaoTest.class,
|
||||
RegistryTest.class,
|
||||
ReservedListSqlDaoTest.class,
|
||||
RegistryLockDaoTest.class,
|
||||
SignedMarkRevocationListDaoTest.class,
|
||||
Spec11ThreatMatchTest.class,
|
||||
// AfterSuiteTest must be the last entry. See class javadoc for details.
|
||||
AfterSuiteTest.class
|
||||
|
||||
@@ -61,7 +61,7 @@ public enum Fixture {
|
||||
createTlds("xn--q9jyb4c", "example");
|
||||
|
||||
// Used for OT&E TLDs
|
||||
persistPremiumList("default_sandbox_list");
|
||||
persistPremiumList("default_sandbox_list", "sandbox,USD 1000");
|
||||
|
||||
try {
|
||||
OteStatsTestHelper.setupCompleteOte("otefinished");
|
||||
|
||||
@@ -49,7 +49,7 @@ abstract class AbstractEppResourceSubject<
|
||||
this.actual = subject;
|
||||
}
|
||||
|
||||
private List<HistoryEntry> getHistoryEntries() {
|
||||
private List<? extends HistoryEntry> getHistoryEntries() {
|
||||
return DatastoreHelper.getHistoryEntries(actual);
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ abstract class AbstractEppResourceSubject<
|
||||
// TODO(weiminyu): Remove after next Truth update
|
||||
@SuppressWarnings("UnnecessaryParentheses")
|
||||
public Which<HistoryEntrySubject> hasHistoryEntryAtIndex(int index) {
|
||||
List<HistoryEntry> historyEntries = getHistoryEntries();
|
||||
List<? extends HistoryEntry> historyEntries = getHistoryEntries();
|
||||
check("getHistoryEntries().size()").that(historyEntries.size()).isAtLeast(index + 1);
|
||||
return new Which<>(
|
||||
check("getHistoryEntries(%s)", index)
|
||||
|
||||
@@ -17,6 +17,7 @@ package google.registry.testing;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.io.Files.asCharSink;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static google.registry.persistence.transaction.TransactionManagerUtil.ofyOrJpaTm;
|
||||
import static google.registry.testing.DatastoreHelper.persistSimpleResources;
|
||||
import static google.registry.testing.DualDatabaseTestInvocationContextProvider.injectTmForDualDatabaseTest;
|
||||
import static google.registry.testing.DualDatabaseTestInvocationContextProvider.restoreTmAfterDualDatabaseTest;
|
||||
@@ -384,6 +385,17 @@ public final class AppEngineExtension implements BeforeEachCallback, AfterEachCa
|
||||
if (isWithDatastoreAndCloudSql()) {
|
||||
injectTmForDualDatabaseTest(context);
|
||||
}
|
||||
ofyOrJpaTm(
|
||||
() -> {
|
||||
if (withDatastore && !withoutCannedData) {
|
||||
loadInitialData();
|
||||
}
|
||||
},
|
||||
() -> {
|
||||
if (withCloudSql && !withJpaUnitTest && !withoutCannedData) {
|
||||
loadInitialData();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -458,9 +470,6 @@ public final class AppEngineExtension implements BeforeEachCallback, AfterEachCa
|
||||
ObjectifyService.initOfy();
|
||||
// Reset id allocation in ObjectifyService so that ids are deterministic in tests.
|
||||
ObjectifyService.resetNextTestId();
|
||||
if (!withoutCannedData) {
|
||||
loadInitialData();
|
||||
}
|
||||
this.ofyTestEntities.forEach(AppEngineExtension::register);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,5 +88,40 @@ public final class CertificateSamples {
|
||||
*/
|
||||
public static final String SAMPLE_CERT2_HASH = "GNd6ZP8/n91t9UTnpxR8aH7aAW4+CpvufYx9ViGbcMY";
|
||||
|
||||
/*
|
||||
* openssl req -new -nodes -x509 -days 200 -newkey rsa:2048 -keyout client1.key -out client1.crt
|
||||
* -subj "/C=US/ST=New York/L=New York/O=Google/OU=domain-registry-test/CN=client1"
|
||||
*/
|
||||
public static final String SAMPLE_CERT3 =
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
+ "MIIDyzCCArOgAwIBAgIUJnhiVrxAxgwkLJzHPm1w/lBoNs4wDQYJKoZIhvcNAQEL\n"
|
||||
+ "BQAwdTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMREwDwYDVQQHDAhO\n"
|
||||
+ "ZXcgWW9yazEPMA0GA1UECgwGR29vZ2xlMR0wGwYDVQQLDBRkb21haW4tcmVnaXN0\n"
|
||||
+ "cnktdGVzdDEQMA4GA1UEAwwHY2xpZW50MTAeFw0yMDEwMTIxNzU5NDFaFw0yMTA0\n"
|
||||
+ "MzAxNzU5NDFaMHUxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazERMA8G\n"
|
||||
+ "A1UEBwwITmV3IFlvcmsxDzANBgNVBAoMBkdvb2dsZTEdMBsGA1UECwwUZG9tYWlu\n"
|
||||
+ "LXJlZ2lzdHJ5LXRlc3QxEDAOBgNVBAMMB2NsaWVudDEwggEiMA0GCSqGSIb3DQEB\n"
|
||||
+ "AQUAA4IBDwAwggEKAoIBAQC0msirO7kXyGEC93stsNYGc02Z77Q2qfHFwaGYkUG8\n"
|
||||
+ "QvOF5SWN+jwTo5Td6Jj26A26a8MLCtK45TCBuMRNcUsHhajhT19ocphO20iY3zhi\n"
|
||||
+ "ycwV1id0iwME4kPd1m57BELRE9tUPOxF81/JQXdR1fwT5KRVHYRDWZhaZ5aBmlZY\n"
|
||||
+ "3t/H9Ly0RBYyApkMaGs3nlb94OOug6SouUfRt02S59ja3wsE2SVF/Eui647OXP7O\n"
|
||||
+ "QdYXofxuqLoNkE8EnAdl43/enGLiCIVd0G2lABibFF+gbxTtfgbg7YtfUZJdL+Mb\n"
|
||||
+ "RAcAtuLXEamNQ9H63JgVF16PlQVCDz2XyI3uCfPpDDiBAgMBAAGjUzBRMB0GA1Ud\n"
|
||||
+ "DgQWBBQ26bWk8qfEBjXs/xZ4m8JZyalnITAfBgNVHSMEGDAWgBQ26bWk8qfEBjXs\n"
|
||||
+ "/xZ4m8JZyalnITAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAZ\n"
|
||||
+ "VcsgslBKanKOieJ5ik2d9qzOMXKfBuWPRFWbkC3t9i5awhHqnGAaj6nICnnMZIyt\n"
|
||||
+ "rdx5lZW5aaQyf0EP/90JAA8Xmty4A6MXmEjQAMiCOpP3A7eeS6Xglgi8IOZl4/bg\n"
|
||||
+ "LonW62TUkilo5IiFt/QklFTeHIjXB+OvA8+2Quqyd+zp7v6KnhXjvaomim78DhwE\n"
|
||||
+ "0PIUnjmiRpGpHfTVioTdfhPHZ2Y93Y8K7juL93sQog9aBu5m9XRJCY6wGyWPE83i\n"
|
||||
+ "kmLfGzjcnaJ6kqCd9xQRFZ0JwHmGlkAQvFoeengbNUqSyjyVgsOoNkEsrWwe/JFO\n"
|
||||
+ "iqBvjEhJlvRoefvkdR98\n"
|
||||
+ "-----END CERTIFICATE-----\n";
|
||||
|
||||
/*
|
||||
* python -c "import sys;print sys.argv[1].decode('hex').encode('base64').strip('\n=')" $(openssl
|
||||
* x509 -fingerprint -sha256 -in client1.crt | grep -Po '(?<=Fingerprint=).*' | sed s/://g)
|
||||
*/
|
||||
public static final String SAMPLE_CERT3_HASH = "GM2tYFuzdpDXN0lqpUXlsvrqk8OdMayryV+4/DOFZ0M";
|
||||
|
||||
private CertificateSamples() {}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user