From b6be22f4471d8cb7d7bea17336d8dabc10a34b54 Mon Sep 17 00:00:00 2001 From: gbrodman Date: Fri, 1 May 2020 17:04:13 -0400 Subject: [PATCH] Implement DatastoreEntity and SqlEntity on more classes (#570) * Implement DatastoreEntity and SqlEntity on more classes For classes that aren't going to transition to SQL, they should just return an empty list of SqlEntities. When reading these in from the commit log manifests, we just won't persist anything to SQL. By having all Datastore entity classes implement DatastoreEntity, we can avoid potential bugs where we forget to transition some entity to SQL, or we forget to have the capability to read back from the commit logs. Note: the EntityTest is still @Ignore'd because there are many SQL and Datastore classes left -- ones that we are still in the process of converting or adding, or ones that require more complicated transitions. Note: Locks and Cursors aren't converted (even though we could) because they're ephemeral * Responses to CR Add a @EntityForTest annotation fix null that snuck in * Keep the test ignored for now --- .../google/registry/model/common/Cursor.java | 10 ++++++- .../model/common/EntityGroupRoot.java | 10 ++++++- .../model/contact/ContactResource.java | 3 +- .../registry/model/domain/DomainBase.java | 2 +- .../registry/model/host/HostResource.java | 4 ++- .../registry/model/ofy/CommitLogBucket.java | 10 ++++++- .../model/ofy/CommitLogCheckpoint.java | 9 +++++- .../model/ofy/CommitLogCheckpointRoot.java | 10 ++++++- .../registry/model/ofy/CommitLogManifest.java | 10 ++++++- .../registry/model/ofy/CommitLogMutation.java | 10 ++++++- .../registry/model/registrar/Registrar.java | 2 +- .../model/registrar/RegistrarContact.java | 4 ++- .../model/registry/label/PremiumList.java | 28 +++++++++++++------ .../model/registry/label/ReservedList.java | 11 +++++++- .../google/registry/model/server/Lock.java | 10 ++++++- .../registry/model/tmch/ClaimsListShard.java | 24 ++++++++++++++-- .../google/registry/schema/cursor/Cursor.java | 10 ++++++- .../registry/schema/domain/RegistryLock.java | 10 ++++++- .../google/registry/schema/server/Lock.java | 10 ++++++- .../registry/schema/tld/PremiumEntry.java | 10 ++++++- .../registry/schema/tld/PremiumList.java | 10 ++++++- .../registry/schema/tld/PremiumListUtils.java | 2 +- .../registry/schema/tld/ReservedList.java | 9 +++++- .../registry/schema/tmch/ClaimsList.java | 10 ++++++- .../converter/BloomFilterConverterTest.java | 2 ++ .../CreateAutoTimestampConverterTest.java | 2 ++ .../converter/CurrencyUnitConverterTest.java | 2 ++ .../converter/DurationConverterTest.java | 2 ++ .../converter/JodaMoneyConverterTest.java | 3 ++ .../UpdateAutoTimestampConverterTest.java | 2 ++ .../registry/schema/replay/EntityTest.java | 10 +++++++ 31 files changed, 217 insertions(+), 34 deletions(-) diff --git a/core/src/main/java/google/registry/model/common/Cursor.java b/core/src/main/java/google/registry/model/common/Cursor.java index 9e8a88c25..1339076af 100644 --- a/core/src/main/java/google/registry/model/common/Cursor.java +++ b/core/src/main/java/google/registry/model/common/Cursor.java @@ -21,6 +21,7 @@ import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.util.DateTimeUtils.START_OF_TIME; import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableList; import com.googlecode.objectify.Key; import com.googlecode.objectify.annotation.Entity; import com.googlecode.objectify.annotation.Id; @@ -28,6 +29,8 @@ import com.googlecode.objectify.annotation.Parent; import google.registry.model.ImmutableObject; import google.registry.model.UpdateAutoTimestamp; import google.registry.model.registry.Registry; +import google.registry.schema.replay.DatastoreEntity; +import google.registry.schema.replay.SqlEntity; import java.util.List; import org.joda.time.DateTime; @@ -37,7 +40,7 @@ import org.joda.time.DateTime; * as scoped on {@link EntityGroupRoot}. */ @Entity -public class Cursor extends ImmutableObject { +public class Cursor extends ImmutableObject implements DatastoreEntity { /** The types of cursors, used as the string id field for each cursor in Datastore. */ public enum CursorType { @@ -134,6 +137,11 @@ public class Cursor extends ImmutableObject { return CursorType.valueOf(String.join("_", id.subList(1, id.size()))); } + @Override + public ImmutableList toSqlEntities() { + return ImmutableList.of(); // Cursors are not converted since they are ephemeral + } + /** * Checks that the type of the scoped object (or null) matches the required type for the specified * cursor (or null, if the cursor is a global cursor). diff --git a/core/src/main/java/google/registry/model/common/EntityGroupRoot.java b/core/src/main/java/google/registry/model/common/EntityGroupRoot.java index 29bc9db3f..11a9af336 100644 --- a/core/src/main/java/google/registry/model/common/EntityGroupRoot.java +++ b/core/src/main/java/google/registry/model/common/EntityGroupRoot.java @@ -14,10 +14,13 @@ package google.registry.model.common; +import com.google.common.collect.ImmutableList; import com.googlecode.objectify.Key; import com.googlecode.objectify.annotation.Entity; import com.googlecode.objectify.annotation.Id; import google.registry.model.BackupGroupRoot; +import google.registry.schema.replay.DatastoreEntity; +import google.registry.schema.replay.SqlEntity; /** * The root key for the entity group which is known as the cross-tld entity group for historical @@ -34,7 +37,7 @@ import google.registry.model.BackupGroupRoot; * the entity group for the single namespace where global data applicable for all TLDs lived. */ @Entity -public class EntityGroupRoot extends BackupGroupRoot { +public class EntityGroupRoot extends BackupGroupRoot implements DatastoreEntity { @SuppressWarnings("unused") @Id @@ -44,4 +47,9 @@ public class EntityGroupRoot extends BackupGroupRoot { public static Key getCrossTldKey() { return Key.create(EntityGroupRoot.class, "cross-tld"); } + + @Override + public ImmutableList toSqlEntities() { + return ImmutableList.of(); // not persisted in SQL + } } diff --git a/core/src/main/java/google/registry/model/contact/ContactResource.java b/core/src/main/java/google/registry/model/contact/ContactResource.java index f459677ae..ad526f9f7 100644 --- a/core/src/main/java/google/registry/model/contact/ContactResource.java +++ b/core/src/main/java/google/registry/model/contact/ContactResource.java @@ -30,6 +30,7 @@ import google.registry.model.annotations.ExternalMessagingName; import google.registry.model.annotations.ReportedOn; import google.registry.model.contact.PostalInfo.Type; import google.registry.model.transfer.TransferData; +import google.registry.schema.replay.DatastoreAndSqlEntity; import java.util.Objects; import java.util.Optional; import java.util.stream.Stream; @@ -60,7 +61,7 @@ import org.joda.time.DateTime; }) @ExternalMessagingName("contact") public class ContactResource extends EppResource - implements ForeignKeyedEppResource, ResourceWithTransferData { + implements DatastoreAndSqlEntity, ForeignKeyedEppResource, ResourceWithTransferData { /** * Unique identifier for this contact. diff --git a/core/src/main/java/google/registry/model/domain/DomainBase.java b/core/src/main/java/google/registry/model/domain/DomainBase.java index 3e6127a72..50fbc01f7 100644 --- a/core/src/main/java/google/registry/model/domain/DomainBase.java +++ b/core/src/main/java/google/registry/model/domain/DomainBase.java @@ -107,7 +107,7 @@ import org.joda.time.Interval; }) @ExternalMessagingName("domain") public class DomainBase extends EppResource - implements ForeignKeyedEppResource, ResourceWithTransferData, DatastoreAndSqlEntity { + implements DatastoreAndSqlEntity, ForeignKeyedEppResource, ResourceWithTransferData { /** The max number of years that a domain can be registered for, as set by ICANN policy. */ public static final int MAX_REGISTRATION_YEARS = 10; diff --git a/core/src/main/java/google/registry/model/host/HostResource.java b/core/src/main/java/google/registry/model/host/HostResource.java index 4e806d143..d51f1ffcb 100644 --- a/core/src/main/java/google/registry/model/host/HostResource.java +++ b/core/src/main/java/google/registry/model/host/HostResource.java @@ -35,6 +35,7 @@ import google.registry.model.domain.DomainBase; import google.registry.model.transfer.TransferData; import google.registry.persistence.VKey; import google.registry.persistence.WithStringVKey; +import google.registry.schema.replay.DatastoreAndSqlEntity; import java.net.InetAddress; import java.util.Optional; import java.util.Set; @@ -55,7 +56,8 @@ import org.joda.time.DateTime; @javax.persistence.Entity @ExternalMessagingName("host") @WithStringVKey -public class HostResource extends EppResource implements ForeignKeyedEppResource { +public class HostResource extends EppResource + implements DatastoreAndSqlEntity, ForeignKeyedEppResource { /** * Fully qualified hostname, which is a unique identifier for this host. diff --git a/core/src/main/java/google/registry/model/ofy/CommitLogBucket.java b/core/src/main/java/google/registry/model/ofy/CommitLogBucket.java index f1f5dbe28..bf9266e61 100644 --- a/core/src/main/java/google/registry/model/ofy/CommitLogBucket.java +++ b/core/src/main/java/google/registry/model/ofy/CommitLogBucket.java @@ -22,6 +22,7 @@ import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.util.DateTimeUtils.START_OF_TIME; import com.google.common.collect.ContiguousSet; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Range; @@ -33,6 +34,8 @@ import google.registry.model.Buildable; import google.registry.model.ImmutableObject; import google.registry.model.annotations.NotBackedUp; import google.registry.model.annotations.NotBackedUp.Reason; +import google.registry.schema.replay.DatastoreEntity; +import google.registry.schema.replay.SqlEntity; import google.registry.util.NonFinalForTesting; import java.util.Random; import java.util.function.Supplier; @@ -51,7 +54,7 @@ import org.joda.time.DateTime; */ @Entity @NotBackedUp(reason = Reason.COMMIT_LOGS) -public class CommitLogBucket extends ImmutableObject implements Buildable { +public class CommitLogBucket extends ImmutableObject implements Buildable, DatastoreEntity { /** * Ranges from 1 to {@link RegistryConfig#getCommitLogBucketCount()}, inclusive; starts at 1 since @@ -70,6 +73,11 @@ public class CommitLogBucket extends ImmutableObject implements Buildable { return lastWrittenTime; } + @Override + public ImmutableList toSqlEntities() { + return ImmutableList.of(); // not persisted in SQL + } + /** * Returns the key for the specified bucket ID. * diff --git a/core/src/main/java/google/registry/model/ofy/CommitLogCheckpoint.java b/core/src/main/java/google/registry/model/ofy/CommitLogCheckpoint.java index 771725723..6a9fb712b 100644 --- a/core/src/main/java/google/registry/model/ofy/CommitLogCheckpoint.java +++ b/core/src/main/java/google/registry/model/ofy/CommitLogCheckpoint.java @@ -27,6 +27,8 @@ import com.googlecode.objectify.annotation.Parent; import google.registry.model.ImmutableObject; import google.registry.model.annotations.NotBackedUp; import google.registry.model.annotations.NotBackedUp.Reason; +import google.registry.schema.replay.DatastoreEntity; +import google.registry.schema.replay.SqlEntity; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -44,7 +46,7 @@ import org.joda.time.DateTime; */ @Entity @NotBackedUp(reason = Reason.COMMIT_LOGS) -public class CommitLogCheckpoint extends ImmutableObject { +public class CommitLogCheckpoint extends ImmutableObject implements DatastoreEntity { /** Shared singleton parent entity for commit log checkpoints. */ @Parent @@ -71,6 +73,11 @@ public class CommitLogCheckpoint extends ImmutableObject { return builder.build(); } + @Override + public ImmutableList toSqlEntities() { + return ImmutableList.of(); // not persisted in SQL + } + /** * Creates a CommitLogCheckpoint for the given wall time and bucket checkpoint times, specified as * a map from bucket ID to bucket commit timestamp. diff --git a/core/src/main/java/google/registry/model/ofy/CommitLogCheckpointRoot.java b/core/src/main/java/google/registry/model/ofy/CommitLogCheckpointRoot.java index 041b8e89d..79bc14b7c 100644 --- a/core/src/main/java/google/registry/model/ofy/CommitLogCheckpointRoot.java +++ b/core/src/main/java/google/registry/model/ofy/CommitLogCheckpointRoot.java @@ -17,12 +17,15 @@ package google.registry.model.ofy; import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.util.DateTimeUtils.START_OF_TIME; +import com.google.common.collect.ImmutableList; import com.googlecode.objectify.Key; import com.googlecode.objectify.annotation.Entity; import com.googlecode.objectify.annotation.Id; import google.registry.model.ImmutableObject; import google.registry.model.annotations.NotBackedUp; import google.registry.model.annotations.NotBackedUp.Reason; +import google.registry.schema.replay.DatastoreEntity; +import google.registry.schema.replay.SqlEntity; import org.joda.time.DateTime; /** @@ -30,7 +33,7 @@ import org.joda.time.DateTime; */ @Entity @NotBackedUp(reason = Reason.COMMIT_LOGS) -public class CommitLogCheckpointRoot extends ImmutableObject { +public class CommitLogCheckpointRoot extends ImmutableObject implements DatastoreEntity { public static final long SINGLETON_ID = 1; // There is always exactly one of these. @@ -49,6 +52,11 @@ public class CommitLogCheckpointRoot extends ImmutableObject { return lastWrittenTime; } + @Override + public ImmutableList toSqlEntities() { + return ImmutableList.of(); // not persisted in SQL + } + public static CommitLogCheckpointRoot loadRoot() { CommitLogCheckpointRoot root = ofy().load().key(getKey()).now(); return root == null ? new CommitLogCheckpointRoot() : root; diff --git a/core/src/main/java/google/registry/model/ofy/CommitLogManifest.java b/core/src/main/java/google/registry/model/ofy/CommitLogManifest.java index b75be844e..5bc07ed8f 100644 --- a/core/src/main/java/google/registry/model/ofy/CommitLogManifest.java +++ b/core/src/main/java/google/registry/model/ofy/CommitLogManifest.java @@ -17,6 +17,7 @@ package google.registry.model.ofy; import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy; import static org.joda.time.DateTimeZone.UTC; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.googlecode.objectify.Key; import com.googlecode.objectify.annotation.Entity; @@ -25,6 +26,8 @@ import com.googlecode.objectify.annotation.Parent; import google.registry.model.ImmutableObject; import google.registry.model.annotations.NotBackedUp; import google.registry.model.annotations.NotBackedUp.Reason; +import google.registry.schema.replay.DatastoreEntity; +import google.registry.schema.replay.SqlEntity; import java.util.LinkedHashSet; import java.util.Set; import org.joda.time.DateTime; @@ -38,7 +41,7 @@ import org.joda.time.DateTime; */ @Entity @NotBackedUp(reason = Reason.COMMIT_LOGS) -public class CommitLogManifest extends ImmutableObject { +public class CommitLogManifest extends ImmutableObject implements DatastoreEntity { /** Commit log manifests are parented on a random bucket. */ @Parent @@ -67,6 +70,11 @@ public class CommitLogManifest extends ImmutableObject { return nullToEmptyImmutableCopy(deletions); } + @Override + public ImmutableList toSqlEntities() { + return ImmutableList.of(); // not persisted in SQL + } + public static CommitLogManifest create( Key parent, DateTime commitTime, Set> deletions) { CommitLogManifest instance = new CommitLogManifest(); diff --git a/core/src/main/java/google/registry/model/ofy/CommitLogMutation.java b/core/src/main/java/google/registry/model/ofy/CommitLogMutation.java index ffeafe80e..61942b073 100644 --- a/core/src/main/java/google/registry/model/ofy/CommitLogMutation.java +++ b/core/src/main/java/google/registry/model/ofy/CommitLogMutation.java @@ -21,6 +21,7 @@ import static google.registry.model.ofy.ObjectifyService.ofy; import com.google.appengine.api.datastore.KeyFactory; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableList; import com.googlecode.objectify.Key; import com.googlecode.objectify.annotation.Entity; import com.googlecode.objectify.annotation.Id; @@ -28,11 +29,13 @@ import com.googlecode.objectify.annotation.Parent; import google.registry.model.ImmutableObject; import google.registry.model.annotations.NotBackedUp; import google.registry.model.annotations.NotBackedUp.Reason; +import google.registry.schema.replay.DatastoreEntity; +import google.registry.schema.replay.SqlEntity; /** Representation of a saved entity in a {@link CommitLogManifest} (not deletes). */ @Entity @NotBackedUp(reason = Reason.COMMIT_LOGS) -public class CommitLogMutation extends ImmutableObject { +public class CommitLogMutation extends ImmutableObject implements DatastoreEntity { /** The manifest this belongs to. */ @Parent @@ -58,6 +61,11 @@ public class CommitLogMutation extends ImmutableObject { return createFromPbBytes(entityProtoBytes); } + @Override + public ImmutableList toSqlEntities() { + return ImmutableList.of(); // not persisted in SQL + } + /** * Returns a new mutation entity created from an @Entity ImmutableObject instance. * diff --git a/core/src/main/java/google/registry/model/registrar/Registrar.java b/core/src/main/java/google/registry/model/registrar/Registrar.java index 4758e1dda..4594e8eec 100644 --- a/core/src/main/java/google/registry/model/registrar/Registrar.java +++ b/core/src/main/java/google/registry/model/registrar/Registrar.java @@ -109,7 +109,7 @@ import org.joda.time.DateTime; name = "registrar_iana_identifier_idx"), }) public class Registrar extends ImmutableObject - implements Buildable, Jsonifiable, DatastoreAndSqlEntity { + implements Buildable, DatastoreAndSqlEntity, Jsonifiable { /** Represents the type of a registrar entity. */ public enum Type { diff --git a/core/src/main/java/google/registry/model/registrar/RegistrarContact.java b/core/src/main/java/google/registry/model/registrar/RegistrarContact.java index 2255522fe..dce8d9bd4 100644 --- a/core/src/main/java/google/registry/model/registrar/RegistrarContact.java +++ b/core/src/main/java/google/registry/model/registrar/RegistrarContact.java @@ -42,6 +42,7 @@ import google.registry.model.ImmutableObject; import google.registry.model.JsonMapBuilder; import google.registry.model.Jsonifiable; import google.registry.model.annotations.ReportedOn; +import google.registry.schema.replay.DatastoreAndSqlEntity; import java.util.Arrays; import java.util.Map; import java.util.Optional; @@ -68,7 +69,8 @@ import javax.persistence.Transient; @javax.persistence.Index(columnList = "gaeUserId", name = "registrarpoc_gae_user_id_idx") }) // TODO(shicong): Rename the class name to RegistrarPoc after database migration -public class RegistrarContact extends ImmutableObject implements Jsonifiable { +public class RegistrarContact extends ImmutableObject + implements DatastoreAndSqlEntity, Jsonifiable { @Parent @Transient Key parent; diff --git a/core/src/main/java/google/registry/model/registry/label/PremiumList.java b/core/src/main/java/google/registry/model/registry/label/PremiumList.java index a2fdf756e..e94ce784c 100644 --- a/core/src/main/java/google/registry/model/registry/label/PremiumList.java +++ b/core/src/main/java/google/registry/model/registry/label/PremiumList.java @@ -31,6 +31,7 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader.InvalidCacheLoadException; import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableList; import com.google.common.hash.BloomFilter; import com.google.common.util.concurrent.UncheckedExecutionException; import com.googlecode.objectify.Key; @@ -41,6 +42,8 @@ import google.registry.model.Buildable; import google.registry.model.ImmutableObject; import google.registry.model.annotations.ReportedOn; import google.registry.model.registry.Registry; +import google.registry.schema.replay.DatastoreEntity; +import google.registry.schema.replay.SqlEntity; import google.registry.util.NonFinalForTesting; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -53,26 +56,28 @@ import javax.annotation.Nullable; import org.joda.money.Money; import org.joda.time.Duration; -/** - * A premium list entity, persisted to Datastore, that is used to check domain label prices. - */ +/** A premium list entity, persisted to Datastore, that is used to check domain label prices. */ @ReportedOn @Entity -public final class PremiumList extends BaseDomainLabelList { +public final class PremiumList extends BaseDomainLabelList + implements DatastoreEntity { /** Stores the revision key for the set of currently used premium list entry entities. */ Key revisionKey; + @Override + public ImmutableList toSqlEntities() { + return ImmutableList.of(); // PremiumList is dual-written + } + /** Virtual parent entity for premium list entry entities associated with a single revision. */ @ReportedOn @Entity public static class PremiumListRevision extends ImmutableObject { - @Parent - Key parent; + @Parent Key parent; - @Id - long revisionId; + @Id long revisionId; /** * A Bloom filter that is used to determine efficiently and quickly whether a label might be @@ -249,7 +254,7 @@ public final class PremiumList extends BaseDomainLabelList - implements Buildable { + implements Buildable, DatastoreEntity { @Parent Key parent; @@ -266,6 +271,11 @@ public final class PremiumList extends BaseDomainLabelList toSqlEntities() { + return null; + } + /** A builder for constructing {@link PremiumListEntry} objects, since they are immutable. */ public static class Builder extends DomainLabelEntry.Builder { diff --git a/core/src/main/java/google/registry/model/registry/label/ReservedList.java b/core/src/main/java/google/registry/model/registry/label/ReservedList.java index b654c8f13..c9b725a2f 100644 --- a/core/src/main/java/google/registry/model/registry/label/ReservedList.java +++ b/core/src/main/java/google/registry/model/registry/label/ReservedList.java @@ -30,6 +30,7 @@ import com.google.common.base.Splitter; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.MapDifference; @@ -45,6 +46,8 @@ import com.googlecode.objectify.mapper.Mapper; import google.registry.model.Buildable; import google.registry.model.registry.Registry; import google.registry.model.registry.label.DomainLabelMetrics.MetricsReservedListMatch; +import google.registry.schema.replay.DatastoreEntity; +import google.registry.schema.replay.SqlEntity; import google.registry.schema.tld.ReservedList.ReservedEntry; import google.registry.schema.tld.ReservedListDao; import java.util.List; @@ -59,7 +62,8 @@ import org.joda.time.DateTime; */ @Entity public final class ReservedList - extends BaseDomainLabelList { + extends BaseDomainLabelList implements + DatastoreEntity { private static final FluentLogger logger = FluentLogger.forEnclosingClass(); @@ -68,6 +72,11 @@ public final class ReservedList boolean shouldPublish = true; + @Override + public ImmutableList toSqlEntities() { + return ImmutableList.of(); // ReservedList is dual-written + } + /** * A reserved list entry entity, persisted to Datastore, that represents a single label and its * reservation type. diff --git a/core/src/main/java/google/registry/model/server/Lock.java b/core/src/main/java/google/registry/model/server/Lock.java index 1687e2e7e..962a93319 100644 --- a/core/src/main/java/google/registry/model/server/Lock.java +++ b/core/src/main/java/google/registry/model/server/Lock.java @@ -22,12 +22,15 @@ import static google.registry.util.DateTimeUtils.isAtOrAfter; import com.google.auto.value.AutoValue; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; import com.google.common.flogger.FluentLogger; import com.googlecode.objectify.annotation.Entity; import com.googlecode.objectify.annotation.Id; import google.registry.model.ImmutableObject; import google.registry.model.annotations.NotBackedUp; import google.registry.model.annotations.NotBackedUp.Reason; +import google.registry.schema.replay.DatastoreEntity; +import google.registry.schema.replay.SqlEntity; import google.registry.util.RequestStatusChecker; import google.registry.util.RequestStatusCheckerImpl; import java.io.Serializable; @@ -47,7 +50,7 @@ import org.joda.time.Duration; */ @Entity @NotBackedUp(reason = Reason.TRANSIENT) -public class Lock extends ImmutableObject implements Serializable { +public class Lock extends ImmutableObject implements DatastoreEntity, Serializable { private static final long serialVersionUID = 756397280691684645L; private static final FluentLogger logger = FluentLogger.forEnclosingClass(); @@ -256,4 +259,9 @@ public class Lock extends ImmutableObject implements Serializable { } }); } + + @Override + public ImmutableList toSqlEntities() { + return ImmutableList.of(); // Locks are not converted since they are ephemeral + } } diff --git a/core/src/main/java/google/registry/model/tmch/ClaimsListShard.java b/core/src/main/java/google/registry/model/tmch/ClaimsListShard.java index f33072f23..3e81b862b 100644 --- a/core/src/main/java/google/registry/model/tmch/ClaimsListShard.java +++ b/core/src/main/java/google/registry/model/tmch/ClaimsListShard.java @@ -26,6 +26,7 @@ import static google.registry.util.DateTimeUtils.START_OF_TIME; 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.MapDifference; import com.google.common.collect.MapDifference.ValueDifference; @@ -44,6 +45,8 @@ import google.registry.model.annotations.NotBackedUp; import google.registry.model.annotations.NotBackedUp.Reason; import google.registry.model.annotations.VirtualEntity; import google.registry.model.common.CrossTldSingleton; +import google.registry.schema.replay.DatastoreEntity; +import google.registry.schema.replay.SqlEntity; import google.registry.schema.tmch.ClaimsList; import google.registry.schema.tmch.ClaimsListDao; import google.registry.util.CollectionUtils; @@ -75,7 +78,7 @@ import org.joda.time.DateTime; */ @Entity @NotBackedUp(reason = Reason.EXTERNALLY_SOURCED) -public class ClaimsListShard extends ImmutableObject { +public class ClaimsListShard extends ImmutableObject implements DatastoreEntity { private static final FluentLogger logger = FluentLogger.forEnclosingClass(); @@ -289,10 +292,15 @@ public class ClaimsListShard extends ImmutableObject { } } + @Override + public ImmutableList toSqlEntities() { + return ImmutableList.of(); // ClaimsLists are dually written + } + /** Virtual parent entity for claims list shards of a specific revision. */ @Entity @VirtualEntity - public static class ClaimsListRevision extends ImmutableObject { + public static class ClaimsListRevision extends ImmutableObject implements DatastoreEntity { @Parent Key parent; @@ -311,6 +319,11 @@ public class ClaimsListShard extends ImmutableObject { public static Key createKey() { return createKey(new ClaimsListSingleton()); } + + @Override + public ImmutableList toSqlEntities() { + return ImmutableList.of(); // ClaimsLists are dually written + } } /** @@ -319,7 +332,7 @@ public class ClaimsListShard extends ImmutableObject { */ @Entity @NotBackedUp(reason = Reason.EXTERNALLY_SOURCED) - public static class ClaimsListSingleton extends CrossTldSingleton { + public static class ClaimsListSingleton extends CrossTldSingleton implements DatastoreEntity { Key activeRevision; static ClaimsListSingleton create(Key revision) { @@ -332,6 +345,11 @@ public class ClaimsListShard extends ImmutableObject { public void setActiveRevision(Key revision) { activeRevision = revision; } + + @Override + public ImmutableList toSqlEntities() { + return ImmutableList.of(); // ClaimsLists are dually written + } } /** diff --git a/core/src/main/java/google/registry/schema/cursor/Cursor.java b/core/src/main/java/google/registry/schema/cursor/Cursor.java index ad9f5e2c2..399ce29db 100644 --- a/core/src/main/java/google/registry/schema/cursor/Cursor.java +++ b/core/src/main/java/google/registry/schema/cursor/Cursor.java @@ -16,10 +16,13 @@ package google.registry.schema.cursor; import static com.google.appengine.api.search.checkers.Preconditions.checkNotNull; +import com.google.common.collect.ImmutableList; import google.registry.model.ImmutableObject; import google.registry.model.UpdateAutoTimestamp; import google.registry.model.common.Cursor.CursorType; import google.registry.schema.cursor.Cursor.CursorId; +import google.registry.schema.replay.DatastoreEntity; +import google.registry.schema.replay.SqlEntity; import google.registry.util.DateTimeUtils; import java.io.Serializable; import java.time.ZonedDateTime; @@ -38,7 +41,7 @@ import org.joda.time.DateTime; @Entity @Table @IdClass(CursorId.class) -public class Cursor { +public class Cursor implements SqlEntity { @Enumerated(EnumType.STRING) @Column(nullable = false) @@ -100,6 +103,11 @@ public class Cursor { return lastUpdateTime.getTimestamp(); } + @Override + public ImmutableList toDatastoreEntities() { + return ImmutableList.of(); // Cursors are not converted since they are ephemeral + } + static class CursorId extends ImmutableObject implements Serializable { public CursorType type; diff --git a/core/src/main/java/google/registry/schema/domain/RegistryLock.java b/core/src/main/java/google/registry/schema/domain/RegistryLock.java index f6b2ca4e2..e20134fa3 100644 --- a/core/src/main/java/google/registry/schema/domain/RegistryLock.java +++ b/core/src/main/java/google/registry/schema/domain/RegistryLock.java @@ -19,10 +19,13 @@ import static google.registry.util.DateTimeUtils.isBeforeOrAt; import static google.registry.util.DateTimeUtils.toZonedDateTime; import static google.registry.util.PreconditionsUtils.checkArgumentNotNull; +import com.google.common.collect.ImmutableList; import google.registry.model.Buildable; import google.registry.model.CreateAutoTimestamp; import google.registry.model.ImmutableObject; import google.registry.model.UpdateAutoTimestamp; +import google.registry.schema.replay.DatastoreEntity; +import google.registry.schema.replay.SqlEntity; import google.registry.util.DateTimeUtils; import java.time.ZonedDateTime; import java.util.Optional; @@ -73,7 +76,7 @@ import org.joda.time.Duration; @Index(name = "idx_registry_lock_verification_code", columnList = "verificationCode"), @Index(name = "idx_registry_lock_registrar_id", columnList = "registrarId") }) -public final class RegistryLock extends ImmutableObject implements Buildable { +public final class RegistryLock extends ImmutableObject implements Buildable, SqlEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -230,6 +233,11 @@ public final class RegistryLock extends ImmutableObject implements Buildable { return new Builder(clone(this)); } + @Override + public ImmutableList toDatastoreEntities() { + return ImmutableList.of(); // not stored in Datastore + } + /** Builder for {@link google.registry.schema.domain.RegistryLock}. */ public static class Builder extends Buildable.Builder { public Builder() {} diff --git a/core/src/main/java/google/registry/schema/server/Lock.java b/core/src/main/java/google/registry/schema/server/Lock.java index 6ddf8f818..1b3ea8f2f 100644 --- a/core/src/main/java/google/registry/schema/server/Lock.java +++ b/core/src/main/java/google/registry/schema/server/Lock.java @@ -16,7 +16,10 @@ package google.registry.schema.server; import static google.registry.util.PreconditionsUtils.checkArgumentNotNull; +import com.google.common.collect.ImmutableList; import google.registry.model.ImmutableObject; +import google.registry.schema.replay.DatastoreEntity; +import google.registry.schema.replay.SqlEntity; import google.registry.schema.server.Lock.LockId; import google.registry.util.DateTimeUtils; import java.io.Serializable; @@ -40,7 +43,7 @@ import org.joda.time.Duration; @Entity @Table @IdClass(LockId.class) -public class Lock { +public class Lock implements SqlEntity { /** The resource name used to create the lock. */ @Column(nullable = false) @@ -116,6 +119,11 @@ public class Lock { return new Lock(resourceName, GLOBAL, requestLogId, acquiredTime, leaseLength); } + @Override + public ImmutableList toDatastoreEntities() { + return ImmutableList.of(); // Locks are not converted since they are ephemeral + } + static class LockId extends ImmutableObject implements Serializable { String resourceName; diff --git a/core/src/main/java/google/registry/schema/tld/PremiumEntry.java b/core/src/main/java/google/registry/schema/tld/PremiumEntry.java index 262409b21..cc5068ff4 100644 --- a/core/src/main/java/google/registry/schema/tld/PremiumEntry.java +++ b/core/src/main/java/google/registry/schema/tld/PremiumEntry.java @@ -14,7 +14,10 @@ package google.registry.schema.tld; +import com.google.common.collect.ImmutableList; import google.registry.model.ImmutableObject; +import google.registry.schema.replay.DatastoreEntity; +import google.registry.schema.replay.SqlEntity; import java.io.Serializable; import java.math.BigDecimal; import javax.persistence.Column; @@ -27,7 +30,7 @@ import javax.persistence.Id; *

These are not persisted directly, but rather, using {@link PremiumList#getLabelsToPrices()}. */ @Entity -public class PremiumEntry extends ImmutableObject implements Serializable { +public class PremiumEntry extends ImmutableObject implements Serializable, SqlEntity { @Id @Column(nullable = false) @@ -41,4 +44,9 @@ public class PremiumEntry extends ImmutableObject implements Serializable { String domainLabel; private PremiumEntry() {} + + @Override + public ImmutableList toDatastoreEntities() { + return ImmutableList.of(); // PremiumList is dually-written + } } diff --git a/core/src/main/java/google/registry/schema/tld/PremiumList.java b/core/src/main/java/google/registry/schema/tld/PremiumList.java index 595da5e87..6b45c5358 100644 --- a/core/src/main/java/google/registry/schema/tld/PremiumList.java +++ b/core/src/main/java/google/registry/schema/tld/PremiumList.java @@ -18,9 +18,12 @@ import static com.google.common.base.Charsets.US_ASCII; import static com.google.common.base.Preconditions.checkState; import static com.google.common.hash.Funnels.stringFunnel; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.hash.BloomFilter; import google.registry.model.CreateAutoTimestamp; +import google.registry.schema.replay.DatastoreEntity; +import google.registry.schema.replay.SqlEntity; import java.math.BigDecimal; import java.util.Map; import javax.annotation.Nullable; @@ -49,7 +52,7 @@ import org.joda.time.DateTime; */ @Entity @Table(indexes = {@Index(columnList = "name", name = "premiumlist_name_idx")}) -public class PremiumList { +public class PremiumList implements SqlEntity { @Column(nullable = false) private String name; @@ -140,4 +143,9 @@ public class PremiumList { public BloomFilter getBloomFilter() { return bloomFilter; } + + @Override + public ImmutableList toDatastoreEntities() { + return ImmutableList.of(); // PremiumList is dual-written + } } diff --git a/core/src/main/java/google/registry/schema/tld/PremiumListUtils.java b/core/src/main/java/google/registry/schema/tld/PremiumListUtils.java index 4fc3c8cdf..33fdbf226 100644 --- a/core/src/main/java/google/registry/schema/tld/PremiumListUtils.java +++ b/core/src/main/java/google/registry/schema/tld/PremiumListUtils.java @@ -54,7 +54,7 @@ public class PremiumListUtils { Map priceAmounts = Maps.transformValues(prices, ple -> ple.getValue().getAmount()); - return google.registry.schema.tld.PremiumList.create(name, currency, priceAmounts); + return PremiumList.create(name, currency, priceAmounts); } private PremiumListUtils() {} diff --git a/core/src/main/java/google/registry/schema/tld/ReservedList.java b/core/src/main/java/google/registry/schema/tld/ReservedList.java index 86a9a27ed..ce77660ae 100644 --- a/core/src/main/java/google/registry/schema/tld/ReservedList.java +++ b/core/src/main/java/google/registry/schema/tld/ReservedList.java @@ -26,6 +26,8 @@ import com.google.common.collect.ImmutableMap; import google.registry.model.CreateAutoTimestamp; import google.registry.model.ImmutableObject; import google.registry.model.registry.label.ReservationType; +import google.registry.schema.replay.DatastoreEntity; +import google.registry.schema.replay.SqlEntity; import java.util.Map; import java.util.stream.Stream; import javax.annotation.Nullable; @@ -53,7 +55,7 @@ import org.joda.time.DateTime; */ @Entity @Table(indexes = {@Index(columnList = "name", name = "reservedlist_name_idx")}) -public class ReservedList extends ImmutableObject { +public class ReservedList extends ImmutableObject implements SqlEntity { @Column(nullable = false) private String name; @@ -76,6 +78,11 @@ public class ReservedList extends ImmutableObject { @MapKeyColumn(name = "domainLabel") private Map labelsToReservations; + @Override + public ImmutableList toDatastoreEntities() { + return ImmutableList.of(); // ReservedList is dual-written\ + } + @Embeddable public static class ReservedEntry extends ImmutableObject { @Column(nullable = false) diff --git a/core/src/main/java/google/registry/schema/tmch/ClaimsList.java b/core/src/main/java/google/registry/schema/tmch/ClaimsList.java index a09767dd4..2d023fa9b 100644 --- a/core/src/main/java/google/registry/schema/tmch/ClaimsList.java +++ b/core/src/main/java/google/registry/schema/tmch/ClaimsList.java @@ -18,8 +18,11 @@ import static com.google.common.base.Preconditions.checkState; import static google.registry.util.DateTimeUtils.toJodaDateTime; import static google.registry.util.DateTimeUtils.toZonedDateTime; +import com.google.common.collect.ImmutableList; import google.registry.model.CreateAutoTimestamp; import google.registry.model.ImmutableObject; +import google.registry.schema.replay.DatastoreEntity; +import google.registry.schema.replay.SqlEntity; import java.time.ZonedDateTime; import java.util.Map; import java.util.Optional; @@ -46,7 +49,7 @@ import org.joda.time.DateTime; */ @Entity @Table -public class ClaimsList extends ImmutableObject { +public class ClaimsList extends ImmutableObject implements SqlEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column @@ -105,4 +108,9 @@ public class ClaimsList extends ImmutableObject { public Optional getClaimKey(String label) { return Optional.ofNullable(labelsToKeys.get(label)); } + + @Override + public ImmutableList toDatastoreEntities() { + return ImmutableList.of(); // ClaimsList is dual-written + } } diff --git a/core/src/test/java/google/registry/persistence/converter/BloomFilterConverterTest.java b/core/src/test/java/google/registry/persistence/converter/BloomFilterConverterTest.java index e6d8fa44c..91eb2551a 100644 --- a/core/src/test/java/google/registry/persistence/converter/BloomFilterConverterTest.java +++ b/core/src/test/java/google/registry/persistence/converter/BloomFilterConverterTest.java @@ -23,6 +23,7 @@ import com.google.common.hash.BloomFilter; import google.registry.model.ImmutableObject; import google.registry.persistence.transaction.JpaTestRules; import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestRule; +import google.registry.schema.replay.EntityTest.EntityForTesting; import javax.persistence.Entity; import javax.persistence.Id; import org.junit.Rule; @@ -50,6 +51,7 @@ public class BloomFilterConverterTest { } @Entity(name = "TestEntity") // Override entity name to avoid the nested class reference. + @EntityForTesting public static class TestEntity extends ImmutableObject { @Id String name = "id"; diff --git a/core/src/test/java/google/registry/persistence/converter/CreateAutoTimestampConverterTest.java b/core/src/test/java/google/registry/persistence/converter/CreateAutoTimestampConverterTest.java index 56f5d003c..b75753d88 100644 --- a/core/src/test/java/google/registry/persistence/converter/CreateAutoTimestampConverterTest.java +++ b/core/src/test/java/google/registry/persistence/converter/CreateAutoTimestampConverterTest.java @@ -20,6 +20,7 @@ import google.registry.model.CreateAutoTimestamp; import google.registry.model.ImmutableObject; import google.registry.persistence.transaction.JpaTestRules; import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestRule; +import google.registry.schema.replay.EntityTest.EntityForTesting; import google.registry.testing.FakeClock; import javax.persistence.Entity; import javax.persistence.Id; @@ -66,6 +67,7 @@ public class CreateAutoTimestampConverterTest { } @Entity(name = "TestEntity") // Override entity name to avoid the nested class reference. + @EntityForTesting public static class TestEntity extends ImmutableObject { @Id String name; diff --git a/core/src/test/java/google/registry/persistence/converter/CurrencyUnitConverterTest.java b/core/src/test/java/google/registry/persistence/converter/CurrencyUnitConverterTest.java index 64de67727..790e25b74 100644 --- a/core/src/test/java/google/registry/persistence/converter/CurrencyUnitConverterTest.java +++ b/core/src/test/java/google/registry/persistence/converter/CurrencyUnitConverterTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertThrows; import google.registry.model.ImmutableObject; import google.registry.persistence.transaction.JpaTestRules; import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestRule; +import google.registry.schema.replay.EntityTest.EntityForTesting; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.PersistenceException; @@ -78,6 +79,7 @@ public class CurrencyUnitConverterTest { } @Entity(name = "TestEntity") // Override entity name to avoid the nested class reference. + @EntityForTesting public static class TestEntity extends ImmutableObject { @Id String name = "id"; diff --git a/core/src/test/java/google/registry/persistence/converter/DurationConverterTest.java b/core/src/test/java/google/registry/persistence/converter/DurationConverterTest.java index c8e801bb2..c87b2e2c6 100644 --- a/core/src/test/java/google/registry/persistence/converter/DurationConverterTest.java +++ b/core/src/test/java/google/registry/persistence/converter/DurationConverterTest.java @@ -20,6 +20,7 @@ import static google.registry.persistence.transaction.TransactionManagerFactory. import google.registry.model.ImmutableObject; import google.registry.persistence.transaction.JpaTestRules; import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestRule; +import google.registry.schema.replay.EntityTest.EntityForTesting; import java.math.BigInteger; import javax.persistence.Entity; import javax.persistence.Id; @@ -65,6 +66,7 @@ public class DurationConverterTest { } @Entity(name = "TestEntity") // Override entity name to avoid the nested class reference. + @EntityForTesting public static class TestEntity extends ImmutableObject { @Id String name = "id"; diff --git a/core/src/test/java/google/registry/persistence/converter/JodaMoneyConverterTest.java b/core/src/test/java/google/registry/persistence/converter/JodaMoneyConverterTest.java index a892b870c..67eff7ffd 100644 --- a/core/src/test/java/google/registry/persistence/converter/JodaMoneyConverterTest.java +++ b/core/src/test/java/google/registry/persistence/converter/JodaMoneyConverterTest.java @@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableMap; import google.registry.model.ImmutableObject; import google.registry.persistence.transaction.JpaTestRules; import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestRule; +import google.registry.schema.replay.EntityTest.EntityForTesting; import java.math.BigDecimal; import java.util.Arrays; import java.util.List; @@ -149,6 +150,7 @@ public class JodaMoneyConverterTest { // Override entity name to exclude outer-class name in table name. Not necessary if class is not // inner class. The double quotes are added to conform to our schema generation convention. @Entity(name = "\"TestEntity\"") + @EntityForTesting public static class TestEntity extends ImmutableObject { @Id String name = "id"; @@ -164,6 +166,7 @@ public class JodaMoneyConverterTest { // See comments on the annotation for TestEntity above for reason. @Entity(name = "\"ComplexTestEntity\"") + @EntityForTesting // This entity is used to test column override for embedded fields and collections. public static class ComplexTestEntity extends ImmutableObject { diff --git a/core/src/test/java/google/registry/persistence/converter/UpdateAutoTimestampConverterTest.java b/core/src/test/java/google/registry/persistence/converter/UpdateAutoTimestampConverterTest.java index 4878a46ef..a6aa107a4 100644 --- a/core/src/test/java/google/registry/persistence/converter/UpdateAutoTimestampConverterTest.java +++ b/core/src/test/java/google/registry/persistence/converter/UpdateAutoTimestampConverterTest.java @@ -20,6 +20,7 @@ import google.registry.model.ImmutableObject; import google.registry.model.UpdateAutoTimestamp; import google.registry.persistence.transaction.JpaTestRules; import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestRule; +import google.registry.schema.replay.EntityTest.EntityForTesting; import google.registry.testing.FakeClock; import javax.persistence.Entity; import javax.persistence.Id; @@ -77,6 +78,7 @@ public class UpdateAutoTimestampConverterTest { } @Entity(name = "TestEntity") // Override entity name to avoid the nested class reference. + @EntityForTesting public static class TestEntity extends ImmutableObject { @Id String name; diff --git a/core/src/test/java/google/registry/schema/replay/EntityTest.java b/core/src/test/java/google/registry/schema/replay/EntityTest.java index 7f430b5bf..86d5f5166 100644 --- a/core/src/test/java/google/registry/schema/replay/EntityTest.java +++ b/core/src/test/java/google/registry/schema/replay/EntityTest.java @@ -22,6 +22,10 @@ import io.github.classgraph.ClassGraph; import io.github.classgraph.ClassInfo; import io.github.classgraph.ClassInfoList; import io.github.classgraph.ScanResult; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import org.junit.Ignore; import org.junit.Test; @@ -59,7 +63,13 @@ public class EntityTest { return classInfoList.stream() .filter(ClassInfo::isStandardClass) .map(ClassInfo::loadClass) + .filter(clazz -> !clazz.isAnnotationPresent(EntityForTesting.class)) .map(Class::getName) .collect(toImmutableSet()); } + + /** Entities that are solely used for testing, to avoid scanning them in {@link EntityTest}. */ + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.RUNTIME) + public @interface EntityForTesting {} }