Remove ofy scaffolding from DomainContent and core classes (#1660)

This removes the code that converts between ofy fields and SQL fields in DomainContent and a number of related core classes (basically anything that also needed modification to support the removal from DomainContent).
This commit is contained in:
Michael Muller 2022-06-29 14:39:25 -04:00 committed by GitHub
parent a2fc56e108
commit 68470e5cdf
62 changed files with 740 additions and 914 deletions

View file

@ -26,6 +26,7 @@ import google.registry.flows.EppException.ParameterValuePolicyErrorException;
import google.registry.flows.EppException.ParameterValueSyntaxErrorException; import google.registry.flows.EppException.ParameterValueSyntaxErrorException;
import google.registry.model.contact.ContactAddress; import google.registry.model.contact.ContactAddress;
import google.registry.model.contact.ContactHistory; import google.registry.model.contact.ContactHistory;
import google.registry.model.contact.ContactHistory.ContactHistoryId;
import google.registry.model.contact.ContactResource; import google.registry.model.contact.ContactResource;
import google.registry.model.contact.PostalInfo; import google.registry.model.contact.PostalInfo;
import google.registry.model.poll.PendingActionNotificationResponse.ContactPendingActionNotificationResponse; import google.registry.model.poll.PendingActionNotificationResponse.ContactPendingActionNotificationResponse;
@ -84,7 +85,9 @@ public class ContactFlowUtils {
transferData.getTransferStatus().isApproved(), transferData.getTransferStatus().isApproved(),
transferData.getTransferRequestTrid(), transferData.getTransferRequestTrid(),
now))) now)))
.setParentKey(contactHistoryKey) .setContactHistoryId(
new ContactHistoryId(
contactHistoryKey.getParent().getName(), contactHistoryKey.getId()))
.build(); .build();
} }
@ -96,7 +99,9 @@ public class ContactFlowUtils {
.setEventTime(transferData.getPendingTransferExpirationTime()) .setEventTime(transferData.getPendingTransferExpirationTime())
.setMsg(transferData.getTransferStatus().getMessage()) .setMsg(transferData.getTransferStatus().getMessage())
.setResponseData(ImmutableList.of(createTransferResponse(targetId, transferData))) .setResponseData(ImmutableList.of(createTransferResponse(targetId, transferData)))
.setParentKey(contactHistoryKey) .setContactHistoryId(
new ContactHistoryId(
contactHistoryKey.getParent().getName(), contactHistoryKey.getId()))
.build(); .build();
} }

View file

@ -134,6 +134,8 @@ public final class ContactTransferRequestFlow implements TransactionalFlow {
.asBuilder() .asBuilder()
.setTransferStatus(TransferStatus.PENDING) .setTransferStatus(TransferStatus.PENDING)
.setServerApproveEntities( .setServerApproveEntities(
serverApproveGainingPollMessage.getContactRepoId(),
contactHistoryKey.getId(),
ImmutableSet.of( ImmutableSet.of(
serverApproveGainingPollMessage.createVKey(), serverApproveGainingPollMessage.createVKey(),
serverApproveLosingPollMessage.createVKey())) serverApproveLosingPollMessage.createVKey()))

View file

@ -87,6 +87,7 @@ import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainCommand; import google.registry.model.domain.DomainCommand;
import google.registry.model.domain.DomainCommand.Create; import google.registry.model.domain.DomainCommand.Create;
import google.registry.model.domain.DomainHistory; import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.domain.GracePeriod; import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.Period; import google.registry.model.domain.Period;
import google.registry.model.domain.fee.FeeCreateCommandExtension; import google.registry.model.domain.fee.FeeCreateCommandExtension;
@ -357,7 +358,8 @@ public final class DomainCreateFlow implements TransactionalFlow {
.setIdnTableName(validateDomainNameWithIdnTables(domainName)) .setIdnTableName(validateDomainNameWithIdnTables(domainName))
.setRegistrationExpirationTime(registrationExpirationTime) .setRegistrationExpirationTime(registrationExpirationTime)
.setAutorenewBillingEvent(autorenewBillingEvent.createVKey()) .setAutorenewBillingEvent(autorenewBillingEvent.createVKey())
.setAutorenewPollMessage(autorenewPollMessage.createVKey()) .setAutorenewPollMessage(
autorenewPollMessage.createVKey(), autorenewPollMessage.getHistoryRevisionId())
.setLaunchNotice(hasClaimsNotice ? launchCreate.get().getNotice() : null) .setLaunchNotice(hasClaimsNotice ? launchCreate.get().getNotice() : null)
.setSmdId(signedMarkId) .setSmdId(signedMarkId)
.setDsData(secDnsCreate.map(SecDnsCreateExtension::getDsData).orElse(null)) .setDsData(secDnsCreate.map(SecDnsCreateExtension::getDsData).orElse(null))
@ -576,7 +578,8 @@ public final class DomainCreateFlow implements TransactionalFlow {
.setRegistrarId(registrarId) .setRegistrarId(registrarId)
.setEventTime(registrationExpirationTime) .setEventTime(registrationExpirationTime)
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setParentKey(domainHistoryKey) .setDomainHistoryId(
new DomainHistoryId(domainHistoryKey.getParent().getName(), domainHistoryKey.getId()))
.build(); .build();
} }
@ -608,7 +611,7 @@ public final class DomainCreateFlow implements TransactionalFlow {
ImmutableList.of( ImmutableList.of(
DomainPendingActionNotificationResponse.create( DomainPendingActionNotificationResponse.create(
fullyQualifiedDomainName, true, historyEntry.getTrid(), now))) fullyQualifiedDomainName, true, historyEntry.getTrid(), now)))
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.build(); .build();
} }

View file

@ -66,6 +66,7 @@ import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingEvent; import google.registry.model.billing.BillingEvent;
import google.registry.model.domain.DomainBase; import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory; import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.domain.GracePeriod; import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.fee.BaseFee.FeeType; import google.registry.model.domain.fee.BaseFee.FeeType;
import google.registry.model.domain.fee.Credit; import google.registry.model.domain.fee.Credit;
@ -355,7 +356,8 @@ public final class DomainDeleteFlow implements TransactionalFlow {
ImmutableList.of( ImmutableList.of(
DomainPendingActionNotificationResponse.create( DomainPendingActionNotificationResponse.create(
existingDomain.getDomainName(), true, trid, deletionTime))) existingDomain.getDomainName(), true, trid, deletionTime)))
.setParentKey(domainHistoryKey) .setDomainHistoryId(
new DomainHistoryId(domainHistoryKey.getParent().getName(), domainHistoryKey.getId()))
.build(); .build();
} }
@ -367,7 +369,8 @@ public final class DomainDeleteFlow implements TransactionalFlow {
return new PollMessage.OneTime.Builder() return new PollMessage.OneTime.Builder()
.setRegistrarId(existingDomain.getPersistedCurrentSponsorRegistrarId()) .setRegistrarId(existingDomain.getPersistedCurrentSponsorRegistrarId())
.setEventTime(now) .setEventTime(now)
.setParentKey(domainHistoryKey) .setDomainHistoryId(
new DomainHistoryId(domainHistoryKey.getParent().getName(), domainHistoryKey.getId()))
.setMsg( .setMsg(
String.format( String.format(
"Domain %s was deleted by registry administrator with final deletion effective: %s", "Domain %s was deleted by registry administrator with final deletion effective: %s",

View file

@ -63,7 +63,6 @@ import com.google.common.collect.Multimaps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.collect.Streams; import com.google.common.collect.Streams;
import com.google.common.net.InternetDomainName; import com.google.common.net.InternetDomainName;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.AuthorizationErrorException; import google.registry.flows.EppException.AuthorizationErrorException;
import google.registry.flows.EppException.CommandUseErrorException; import google.registry.flows.EppException.CommandUseErrorException;
@ -89,6 +88,7 @@ import google.registry.model.domain.DomainCommand.CreateOrUpdate;
import google.registry.model.domain.DomainCommand.InvalidReferencesException; import google.registry.model.domain.DomainCommand.InvalidReferencesException;
import google.registry.model.domain.DomainCommand.Update; import google.registry.model.domain.DomainCommand.Update;
import google.registry.model.domain.DomainHistory; import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.domain.ForeignKeyedDesignatedContact; import google.registry.model.domain.ForeignKeyedDesignatedContact;
import google.registry.model.domain.Period; import google.registry.model.domain.Period;
import google.registry.model.domain.fee.BaseFee; import google.registry.model.domain.fee.BaseFee;
@ -592,14 +592,15 @@ public class DomainFlowUtils {
// where all autorenew poll messages had already been delivered (this would cause the poll // where all autorenew poll messages had already been delivered (this would cause the poll
// message to be deleted), and then subsequently the transfer was canceled, rejected, or deleted // message to be deleted), and then subsequently the transfer was canceled, rejected, or deleted
// (which would cause the poll message to be recreated here). // (which would cause the poll message to be recreated here).
Key<PollMessage.Autorenew> existingAutorenewKey = domain.getAutorenewPollMessage().getOfyKey();
PollMessage.Autorenew updatedAutorenewPollMessage = PollMessage.Autorenew updatedAutorenewPollMessage =
autorenewPollMessage.isPresent() autorenewPollMessage.isPresent()
? autorenewPollMessage.get().asBuilder().setAutorenewEndTime(newEndTime).build() ? autorenewPollMessage.get().asBuilder().setAutorenewEndTime(newEndTime).build()
: newAutorenewPollMessage(domain) : newAutorenewPollMessage(domain)
.setId(existingAutorenewKey.getId()) .setId((Long) domain.getAutorenewPollMessage().getSqlKey())
.setAutorenewEndTime(newEndTime) .setAutorenewEndTime(newEndTime)
.setParentKey(existingAutorenewKey.getParent()) .setDomainHistoryId(
new DomainHistoryId(
domain.getRepoId(), domain.getAutorenewPollMessageHistoryId()))
.build(); .build();
// If the resultant autorenew poll message would have no poll messages to deliver, then just // If the resultant autorenew poll message would have no poll messages to deliver, then just

View file

@ -58,6 +58,7 @@ import google.registry.model.billing.BillingEvent.Recurring;
import google.registry.model.domain.DomainBase; import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainCommand.Renew; import google.registry.model.domain.DomainCommand.Renew;
import google.registry.model.domain.DomainHistory; import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.domain.DomainRenewData; import google.registry.model.domain.DomainRenewData;
import google.registry.model.domain.GracePeriod; import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.Period; import google.registry.model.domain.Period;
@ -187,7 +188,9 @@ public final class DomainRenewFlow implements TransactionalFlow {
PollMessage.Autorenew newAutorenewPollMessage = PollMessage.Autorenew newAutorenewPollMessage =
newAutorenewPollMessage(existingDomain) newAutorenewPollMessage(existingDomain)
.setEventTime(newExpirationTime) .setEventTime(newExpirationTime)
.setParentKey(domainHistoryKey) .setDomainHistoryId(
new DomainHistoryId(
domainHistoryKey.getParent().getName(), domainHistoryKey.getId()))
.build(); .build();
// End the old autorenew billing event and poll message now. This may delete the poll message. // End the old autorenew billing event and poll message now. This may delete the poll message.
updateAutorenewRecurrenceEndTime(existingDomain, now); updateAutorenewRecurrenceEndTime(existingDomain, now);
@ -198,7 +201,9 @@ public final class DomainRenewFlow implements TransactionalFlow {
.setLastEppUpdateRegistrarId(registrarId) .setLastEppUpdateRegistrarId(registrarId)
.setRegistrationExpirationTime(newExpirationTime) .setRegistrationExpirationTime(newExpirationTime)
.setAutorenewBillingEvent(newAutorenewEvent.createVKey()) .setAutorenewBillingEvent(newAutorenewEvent.createVKey())
.setAutorenewPollMessage(newAutorenewPollMessage.createVKey()) .setAutorenewPollMessage(
newAutorenewPollMessage.createVKey(),
newAutorenewPollMessage.getHistoryRevisionId())
.addGracePeriod( .addGracePeriod(
GracePeriod.forBillingEvent( GracePeriod.forBillingEvent(
GracePeriodStatus.RENEW, existingDomain.getRepoId(), explicitRenewEvent)) GracePeriodStatus.RENEW, existingDomain.getRepoId(), explicitRenewEvent))

View file

@ -53,6 +53,7 @@ import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.domain.DomainBase; import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainCommand.Update; import google.registry.model.domain.DomainCommand.Update;
import google.registry.model.domain.DomainHistory; import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.domain.fee.BaseFee.FeeType; import google.registry.model.domain.fee.BaseFee.FeeType;
import google.registry.model.domain.fee.Fee; import google.registry.model.domain.fee.Fee;
import google.registry.model.domain.fee.FeeTransformResponseExtension; import google.registry.model.domain.fee.FeeTransformResponseExtension;
@ -173,7 +174,9 @@ public final class DomainRestoreRequestFlow implements TransactionalFlow {
newAutorenewPollMessage(existingDomain) newAutorenewPollMessage(existingDomain)
.setEventTime(newExpirationTime) .setEventTime(newExpirationTime)
.setAutorenewEndTime(END_OF_TIME) .setAutorenewEndTime(END_OF_TIME)
.setParentKey(domainHistoryKey) .setDomainHistoryId(
new DomainHistoryId(
domainHistoryKey.getParent().getName(), domainHistoryKey.getId()))
.build(); .build();
DomainBase newDomain = DomainBase newDomain =
performRestore( performRestore(
@ -245,7 +248,8 @@ public final class DomainRestoreRequestFlow implements TransactionalFlow {
.setGracePeriods(null) .setGracePeriods(null)
.setDeletePollMessage(null) .setDeletePollMessage(null)
.setAutorenewBillingEvent(autorenewEvent.createVKey()) .setAutorenewBillingEvent(autorenewEvent.createVKey())
.setAutorenewPollMessage(autorenewPollMessage.createVKey()) .setAutorenewPollMessage(
autorenewPollMessage.createVKey(), autorenewPollMessage.getHistoryRevisionId())
// Clear the autorenew end time so if it had expired but is now explicitly being restored, // Clear the autorenew end time so if it had expired but is now explicitly being restored,
// it won't immediately be deleted again. // it won't immediately be deleted again.
.setAutorenewEndTime(Optional.empty()) .setAutorenewEndTime(Optional.empty())

View file

@ -51,6 +51,7 @@ import google.registry.model.billing.BillingEvent.Flag;
import google.registry.model.billing.BillingEvent.Reason; import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.domain.DomainBase; import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory; import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.domain.GracePeriod; import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.metadata.MetadataExtension; import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.domain.rgp.GracePeriodStatus; import google.registry.model.domain.rgp.GracePeriodStatus;
@ -176,7 +177,9 @@ public final class DomainTransferApproveFlow implements TransactionalFlow {
.setEventTime(newExpirationTime) .setEventTime(newExpirationTime)
.setAutorenewEndTime(END_OF_TIME) .setAutorenewEndTime(END_OF_TIME)
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setParentKey(domainHistoryKey) .setDomainHistoryId(
new DomainHistoryId(
domainHistoryKey.getParent().getName(), domainHistoryKey.getId()))
.build(); .build();
// Construct the post-transfer domain. // Construct the post-transfer domain.
DomainBase partiallyApprovedDomain = DomainBase partiallyApprovedDomain =
@ -194,7 +197,9 @@ public final class DomainTransferApproveFlow implements TransactionalFlow {
.build()) .build())
.setRegistrationExpirationTime(newExpirationTime) .setRegistrationExpirationTime(newExpirationTime)
.setAutorenewBillingEvent(autorenewEvent.createVKey()) .setAutorenewBillingEvent(autorenewEvent.createVKey())
.setAutorenewPollMessage(gainingClientAutorenewPollMessage.createVKey()) .setAutorenewPollMessage(
gainingClientAutorenewPollMessage.createVKey(),
gainingClientAutorenewPollMessage.getHistoryRevisionId())
// Remove all the old grace periods and add a new one for the transfer. // Remove all the old grace periods and add a new one for the transfer.
.setGracePeriods( .setGracePeriods(
billingEvent billingEvent

View file

@ -208,6 +208,8 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
// Create the transfer data that represents the pending transfer. // Create the transfer data that represents the pending transfer.
DomainTransferData pendingTransferData = DomainTransferData pendingTransferData =
createPendingTransferData( createPendingTransferData(
domainAtTransferTime.getRepoId(),
domainHistoryKey.getId(),
new DomainTransferData.Builder() new DomainTransferData.Builder()
.setTransferRequestTrid(trid) .setTransferRequestTrid(trid)
.setTransferRequestTime(now) .setTransferRequestTime(now)

View file

@ -26,6 +26,7 @@ import google.registry.model.billing.BillingEvent.Flag;
import google.registry.model.billing.BillingEvent.Reason; import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.domain.DomainBase; import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory; import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.domain.GracePeriod; import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.Period; import google.registry.model.domain.Period;
import google.registry.model.domain.rgp.GracePeriodStatus; import google.registry.model.domain.rgp.GracePeriodStatus;
@ -51,6 +52,8 @@ public final class DomainTransferUtils {
/** Sets up {@link TransferData} for a domain with links to entities for server approval. */ /** Sets up {@link TransferData} for a domain with links to entities for server approval. */
public static DomainTransferData createPendingTransferData( public static DomainTransferData createPendingTransferData(
String domainRepoId,
Long historyId,
DomainTransferData.Builder transferDataBuilder, DomainTransferData.Builder transferDataBuilder,
ImmutableSet<TransferServerApproveEntity> serverApproveEntities, ImmutableSet<TransferServerApproveEntity> serverApproveEntities,
Period transferPeriod) { Period transferPeriod) {
@ -82,7 +85,7 @@ public final class DomainTransferUtils {
.map(PollMessage.Autorenew.class::cast) .map(PollMessage.Autorenew.class::cast)
.collect(onlyElement()) .collect(onlyElement())
.createVKey()) .createVKey())
.setServerApproveEntities(serverApproveEntityKeys.build()) .setServerApproveEntities(domainRepoId, historyId, serverApproveEntityKeys.build())
.setTransferPeriod(transferPeriod) .setTransferPeriod(transferPeriod)
.build(); .build();
} }
@ -180,7 +183,8 @@ public final class DomainTransferUtils {
transferData.getTransferStatus().isApproved(), transferData.getTransferStatus().isApproved(),
transferData.getTransferRequestTrid(), transferData.getTransferRequestTrid(),
now))) now)))
.setParentKey(domainHistoryKey) .setDomainHistoryId(
new DomainHistoryId(domainHistoryKey.getParent().getName(), domainHistoryKey.getId()))
.build(); .build();
} }
@ -197,7 +201,8 @@ public final class DomainTransferUtils {
.setResponseData( .setResponseData(
ImmutableList.of( ImmutableList.of(
createTransferResponse(targetId, transferData, extendedRegistrationExpirationTime))) createTransferResponse(targetId, transferData, extendedRegistrationExpirationTime)))
.setParentKey(domainHistoryKey) .setDomainHistoryId(
new DomainHistoryId(domainHistoryKey.getParent().getName(), domainHistoryKey.getId()))
.build(); .build();
} }
@ -228,7 +233,8 @@ public final class DomainTransferUtils {
.setEventTime(serverApproveNewExpirationTime) .setEventTime(serverApproveNewExpirationTime)
.setAutorenewEndTime(END_OF_TIME) .setAutorenewEndTime(END_OF_TIME)
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setParentKey(domainHistoryKey) .setDomainHistoryId(
new DomainHistoryId(domainHistoryKey.getParent().getName(), domainHistoryKey.getId()))
.build(); .build();
} }

View file

@ -66,6 +66,7 @@ import google.registry.flows.domain.DomainFlowUtils.NameserversNotSpecifiedForTl
import google.registry.model.ImmutableObject; import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingEvent; import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Reason; import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.domain.DesignatedContact;
import google.registry.model.domain.DomainBase; import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainCommand.Update; import google.registry.model.domain.DomainCommand.Update;
import google.registry.model.domain.DomainCommand.Update.AddRemove; import google.registry.model.domain.DomainCommand.Update.AddRemove;
@ -243,6 +244,13 @@ public final class DomainUpdateFlow implements TransactionalFlow {
validateRegistrantIsntBeingRemoved(change); validateRegistrantIsntBeingRemoved(change);
Optional<SecDnsUpdateExtension> secDnsUpdate = Optional<SecDnsUpdateExtension> secDnsUpdate =
eppInput.getSingleExtension(SecDnsUpdateExtension.class); eppInput.getSingleExtension(SecDnsUpdateExtension.class);
// We have to verify no duplicate contacts _before_ constructing the domain because it is
// illegal to construct a domain with duplicate contacts.
Sets.SetView<DesignatedContact> newContacts =
Sets.union(Sets.difference(domain.getContacts(), remove.getContacts()), add.getContacts());
validateNoDuplicateContacts(newContacts);
DomainBase.Builder domainBuilder = DomainBase.Builder domainBuilder =
domain domain
.asBuilder() .asBuilder()
@ -263,8 +271,8 @@ public final class DomainUpdateFlow implements TransactionalFlow {
.removeStatusValues(remove.getStatusValues()) .removeStatusValues(remove.getStatusValues())
.addNameservers(add.getNameservers().stream().collect(toImmutableSet())) .addNameservers(add.getNameservers().stream().collect(toImmutableSet()))
.removeNameservers(remove.getNameservers().stream().collect(toImmutableSet())) .removeNameservers(remove.getNameservers().stream().collect(toImmutableSet()))
.addContacts(add.getContacts())
.removeContacts(remove.getContacts()) .removeContacts(remove.getContacts())
.addContacts(add.getContacts())
.setRegistrant(firstNonNull(change.getRegistrant(), domain.getRegistrant())) .setRegistrant(firstNonNull(change.getRegistrant(), domain.getRegistrant()))
.setAuthInfo(firstNonNull(change.getAuthInfo(), domain.getAuthInfo())); .setAuthInfo(firstNonNull(change.getAuthInfo(), domain.getAuthInfo()));
Optional<DomainUpdateSuperuserExtension> superuserExt = Optional<DomainUpdateSuperuserExtension> superuserExt =
@ -286,7 +294,6 @@ public final class DomainUpdateFlow implements TransactionalFlow {
} }
private void validateNewState(DomainBase newDomain) throws EppException { private void validateNewState(DomainBase newDomain) throws EppException {
validateNoDuplicateContacts(newDomain.getContacts());
validateRequiredContactsPresent(newDomain.getRegistrant(), newDomain.getContacts()); validateRequiredContactsPresent(newDomain.getRegistrant(), newDomain.getContacts());
validateDsData(newDomain.getDsData()); validateDsData(newDomain.getDsData());
validateNameserversCountForTld( validateNameserversCountForTld(
@ -360,7 +367,7 @@ public final class DomainUpdateFlow implements TransactionalFlow {
return Optional.ofNullable( return Optional.ofNullable(
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.setEventTime(now) .setEventTime(now)
.setRegistrarId(existingDomain.getCurrentSponsorRegistrarId()) .setRegistrarId(existingDomain.getCurrentSponsorRegistrarId())
.setMsg(msg) .setMsg(msg)

View file

@ -226,7 +226,7 @@ public final class EppResourceUtils {
checkArgument(TransferStatus.PENDING.equals(transferData.getTransferStatus())); checkArgument(TransferStatus.PENDING.equals(transferData.getTransferStatus()));
TransferData.Builder transferDataBuilder = transferData.asBuilder(); TransferData.Builder transferDataBuilder = transferData.asBuilder();
transferDataBuilder.setTransferStatus(TransferStatus.SERVER_APPROVED); transferDataBuilder.setTransferStatus(TransferStatus.SERVER_APPROVED);
transferDataBuilder.setServerApproveEntities(null); transferDataBuilder.setServerApproveEntities(null, null, null);
if (transferData instanceof DomainTransferData) { if (transferData instanceof DomainTransferData) {
((DomainTransferData.Builder) transferDataBuilder) ((DomainTransferData.Builder) transferDataBuilder)
.setServerApproveBillingEvent(null) .setServerApproveBillingEvent(null)

View file

@ -128,7 +128,7 @@ public final class ResourceTransferUtils {
createTransferResponse(newResource, newResource.getTransferData()), createTransferResponse(newResource, newResource.getTransferData()),
createPendingTransferNotificationResponse( createPendingTransferNotificationResponse(
resource, oldTransferData.getTransferRequestTrid(), false, now))) resource, oldTransferData.getTransferRequestTrid(), false, now)))
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.build()); .build());
} }
} }

View file

@ -84,6 +84,10 @@ public class ContactHistory extends HistoryEntry implements UnsafeSerializable {
return super.getId(); return super.getId();
} }
public ContactHistoryId getContactHistoryId() {
return new ContactHistoryId(getContactRepoId(), getId());
}
/** /**
* The values of all the fields on the {@link ContactBase} object after the action represented by * The values of all the fields on the {@link ContactBase} object after the action represented by
* this history object was executed. * this history object was executed.
@ -147,8 +151,7 @@ public class ContactHistory extends HistoryEntry implements UnsafeSerializable {
* *
* <p>This method is private because it is only used by Hibernate. * <p>This method is private because it is only used by Hibernate.
*/ */
@SuppressWarnings("unused") public String getContactRepoId() {
private String getContactRepoId() {
return contactRepoId; return contactRepoId;
} }
@ -157,8 +160,7 @@ public class ContactHistory extends HistoryEntry implements UnsafeSerializable {
* *
* <p>This method is private because it is only used by Hibernate. * <p>This method is private because it is only used by Hibernate.
*/ */
@SuppressWarnings("unused") public long getId() {
private long getId() {
return id; return id;
} }

View file

@ -150,9 +150,7 @@ public class DomainBase extends DomainContent implements ForeignKeyedEppResource
/** Post-load method to eager load the collections. */ /** Post-load method to eager load the collections. */
@PostLoad @PostLoad
@Override
protected void postLoad() { protected void postLoad() {
super.postLoad();
// TODO(b/188044616): Determine why Eager loading doesn't work here. // TODO(b/188044616): Determine why Eager loading doesn't work here.
Hibernate.initialize(dsData); Hibernate.initialize(dsData);
Hibernate.initialize(gracePeriods); Hibernate.initialize(gracePeriods);
@ -190,7 +188,9 @@ public class DomainBase extends DomainContent implements ForeignKeyedEppResource
public Builder copyFrom(DomainContent domainContent) { public Builder copyFrom(DomainContent domainContent) {
this.getInstance().copyUpdateTimestamp(domainContent); this.getInstance().copyUpdateTimestamp(domainContent);
return this.setAuthInfo(domainContent.getAuthInfo()) return this.setAuthInfo(domainContent.getAuthInfo())
.setAutorenewPollMessage(domainContent.getAutorenewPollMessage()) .setAutorenewPollMessage(
domainContent.getAutorenewPollMessage(),
domainContent.getAutorenewPollMessageHistoryId())
.setAutorenewBillingEvent(domainContent.getAutorenewBillingEvent()) .setAutorenewBillingEvent(domainContent.getAutorenewBillingEvent())
.setAutorenewEndTime(domainContent.getAutorenewEndTime()) .setAutorenewEndTime(domainContent.getAutorenewEndTime())
.setContacts(domainContent.getContacts()) .setContacts(domainContent.getContacts())

View file

@ -42,12 +42,10 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Ordering; import com.google.common.collect.Ordering;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.collect.Streams;
import com.googlecode.objectify.Key; import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.Ignore; import com.googlecode.objectify.annotation.Ignore;
import com.googlecode.objectify.annotation.IgnoreSave; import com.googlecode.objectify.annotation.IgnoreSave;
import com.googlecode.objectify.annotation.Index; import com.googlecode.objectify.annotation.Index;
import com.googlecode.objectify.annotation.OnLoad;
import com.googlecode.objectify.condition.IfNull; import com.googlecode.objectify.condition.IfNull;
import google.registry.dns.RefreshDnsAction; import google.registry.dns.RefreshDnsAction;
import google.registry.flows.ResourceFlowUtils; import google.registry.flows.ResourceFlowUtils;
@ -82,7 +80,6 @@ import javax.persistence.Column;
import javax.persistence.Embeddable; import javax.persistence.Embeddable;
import javax.persistence.Embedded; import javax.persistence.Embedded;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
import javax.persistence.PostLoad;
import javax.persistence.Transient; import javax.persistence.Transient;
import org.hibernate.collection.internal.PersistentSet; import org.hibernate.collection.internal.PersistentSet;
import org.joda.time.DateTime; import org.joda.time.DateTime;
@ -139,23 +136,12 @@ public class DomainContent extends EppResource
/** References to hosts that are the nameservers for the domain. */ /** References to hosts that are the nameservers for the domain. */
@EmptySetToNull @Index @Transient Set<VKey<HostResource>> nsHosts; @EmptySetToNull @Index @Transient Set<VKey<HostResource>> nsHosts;
/** /** Contacts. */
* The union of the contacts visible via {@link #getContacts} and {@link #getRegistrant}. VKey<ContactResource> adminContact;
*
* <p>These are stored in one field so that we can query across all contacts at once.
*/
@Transient Set<DesignatedContact> allContacts;
/** VKey<ContactResource> billingContact;
* Contacts as they are stored in cloud SQL. VKey<ContactResource> techContact;
* VKey<ContactResource> registrantContact;
* <p>This information is duplicated in allContacts, and must be kept in sync with it.
*/
@Ignore VKey<ContactResource> adminContact;
@Ignore VKey<ContactResource> billingContact;
@Ignore VKey<ContactResource> techContact;
@Ignore VKey<ContactResource> registrantContact;
/** Authorization info (aka transfer secret) of the domain. */ /** Authorization info (aka transfer secret) of the domain. */
@Embedded @Embedded
@ -165,12 +151,7 @@ public class DomainContent extends EppResource
}) })
DomainAuthInfo authInfo; DomainAuthInfo authInfo;
/** /** Data used to construct DS records for this domain. */
* Data used to construct DS records for this domain.
*
* <p>This is {@literal @}XmlTransient because it needs to be returned under the "extension" tag
* of an info response rather than inside the "infData" tag.
*/
@Transient Set<DelegationSignerData> dsData; @Transient Set<DelegationSignerData> dsData;
/** /**
@ -178,7 +159,6 @@ public class DomainContent extends EppResource
* *
* <p>It's {@literal @}XmlTransient because it's not returned in an info response. * <p>It's {@literal @}XmlTransient because it's not returned in an info response.
*/ */
@IgnoreSave(IfNull.class)
@Embedded @Embedded
@AttributeOverrides({ @AttributeOverrides({
@AttributeOverride(name = "noticeId.tcnId", column = @Column(name = "launch_notice_tcn_id")), @AttributeOverride(name = "noticeId.tcnId", column = @Column(name = "launch_notice_tcn_id")),
@ -218,15 +198,6 @@ public class DomainContent extends EppResource
@Column(name = "deletion_poll_message_id") @Column(name = "deletion_poll_message_id")
VKey<PollMessage.OneTime> deletePollMessage; VKey<PollMessage.OneTime> deletePollMessage;
/**
* History record for the delete poll message.
*
* <p>Here so we can restore the original ofy key from sql.
*/
@Column(name = "deletion_poll_message_history_id")
@Ignore
Long deletePollMessageHistoryId;
/** /**
* The recurring billing event associated with this domain's autorenewals. * The recurring billing event associated with this domain's autorenewals.
* *
@ -238,15 +209,6 @@ public class DomainContent extends EppResource
@Column(name = "billing_recurrence_id") @Column(name = "billing_recurrence_id")
VKey<BillingEvent.Recurring> autorenewBillingEvent; VKey<BillingEvent.Recurring> autorenewBillingEvent;
/**
* History record for the autorenew billing event.
*
* <p>Here so we can restore the original ofy key from sql.
*/
@Column(name = "billing_recurrence_history_id")
@Ignore
Long autorenewBillingEventHistoryId;
/** /**
* The recurring poll message associated with this domain's autorenewals. * The recurring poll message associated with this domain's autorenewals.
* *
@ -332,75 +294,6 @@ public class DomainContent extends EppResource
return Optional.ofNullable(dnsRefreshRequestTime); return Optional.ofNullable(dnsRefreshRequestTime);
} }
@OnLoad
void load() {
// Reconstitute all of the contacts so that they have VKeys.
allContacts =
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 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.cloneAfterOfyLoad(getRepoId()))
.collect(toImmutableSet());
// Restore history record ids.
autorenewPollMessageHistoryId = getHistoryId(autorenewPollMessage);
autorenewBillingEventHistoryId = getHistoryId(autorenewBillingEvent);
deletePollMessageHistoryId = getHistoryId(deletePollMessage);
// Fix PollMessage VKeys.
autorenewPollMessage = PollMessage.Autorenew.convertVKey(autorenewPollMessage);
deletePollMessage = PollMessage.OneTime.convertVKey(deletePollMessage);
dsData =
nullToEmptyImmutableCopy(dsData).stream()
.map(dsData -> dsData.cloneWithDomainRepoId(getRepoId()))
.collect(toImmutableSet());
if (transferData != null) {
transferData.convertVKeys();
}
}
@PostLoad
protected void postLoad() {
// Reconstitute the contact list.
ImmutableSet.Builder<DesignatedContact> contactsBuilder = new ImmutableSet.Builder<>();
if (registrantContact != null) {
contactsBuilder.add(
DesignatedContact.create(DesignatedContact.Type.REGISTRANT, registrantContact));
}
if (billingContact != null) {
contactsBuilder.add(DesignatedContact.create(DesignatedContact.Type.BILLING, billingContact));
}
if (techContact != null) {
contactsBuilder.add(DesignatedContact.create(DesignatedContact.Type.TECH, techContact));
}
if (adminContact != null) {
contactsBuilder.add(DesignatedContact.create(DesignatedContact.Type.ADMIN, adminContact));
}
allContacts = contactsBuilder.build();
// Reconstitute the composite ofy keys from the SQL data.
Key<DomainBase> myKey = Key.create(DomainBase.class, getRepoId());
deletePollMessage = restoreOfyFrom(myKey, deletePollMessage, deletePollMessageHistoryId);
autorenewBillingEvent =
restoreOfyFrom(myKey, autorenewBillingEvent, autorenewBillingEventHistoryId);
autorenewPollMessage =
restoreOfyFrom(myKey, autorenewPollMessage, autorenewPollMessageHistoryId);
if (transferData != null) {
transferData.restoreOfyKeys(myKey);
}
}
public static <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) { if (historyId == null) {
// This is a legacy key (or a null key, in which case this works too) // This is a legacy key (or a null key, in which case this works too)
@ -430,6 +323,10 @@ public class DomainContent extends EppResource
return autorenewPollMessage; return autorenewPollMessage;
} }
public Long getAutorenewPollMessageHistoryId() {
return autorenewPollMessageHistoryId;
}
public ImmutableSet<GracePeriod> getGracePeriods() { public ImmutableSet<GracePeriod> getGracePeriods() {
return nullToEmptyImmutableCopy(gracePeriods); return nullToEmptyImmutableCopy(gracePeriods);
} }
@ -609,7 +506,9 @@ public class DomainContent extends EppResource
// Set the speculatively-written new autorenew events as the domain's autorenew // Set the speculatively-written new autorenew events as the domain's autorenew
// events. // events.
.setAutorenewBillingEvent(transferData.getServerApproveAutorenewEvent()) .setAutorenewBillingEvent(transferData.getServerApproveAutorenewEvent())
.setAutorenewPollMessage(transferData.getServerApproveAutorenewPollMessage()); .setAutorenewPollMessage(
transferData.getServerApproveAutorenewPollMessage(),
transferData.getServerApproveAutorenewPollMessageHistoryId());
if (transferData.getTransferPeriod().getValue() == 1) { if (transferData.getTransferPeriod().getValue() == 1) {
// Set the grace period using a key to the prescheduled transfer billing event. Not using // Set the grace period using a key to the prescheduled transfer billing event. Not using
// GracePeriod.forBillingEvent() here in order to avoid the actual Datastore fetch. // GracePeriod.forBillingEvent() here in order to avoid the actual Datastore fetch.
@ -731,9 +630,7 @@ public class DomainContent extends EppResource
/** Associated contacts for the domain (other than registrant). */ /** Associated contacts for the domain (other than registrant). */
public ImmutableSet<DesignatedContact> getContacts() { public ImmutableSet<DesignatedContact> getContacts() {
return nullToEmpty(allContacts).stream() return getAllContacts(false);
.filter(IS_REGISTRANT.negate())
.collect(toImmutableSet());
} }
public DomainAuthInfo getAuthInfo() { public DomainAuthInfo getAuthInfo() {
@ -742,12 +639,29 @@ public class DomainContent extends EppResource
/** Returns all referenced contacts from this domain. */ /** Returns all referenced contacts from this domain. */
public ImmutableSet<VKey<ContactResource>> getReferencedContacts() { public ImmutableSet<VKey<ContactResource>> getReferencedContacts() {
return nullToEmptyImmutableCopy(allContacts).stream() return nullToEmptyImmutableCopy(getAllContacts(true)).stream()
.map(DesignatedContact::getContactKey) .map(DesignatedContact::getContactKey)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.collect(toImmutableSet()); .collect(toImmutableSet());
} }
private ImmutableSet<DesignatedContact> getAllContacts(boolean includeRegistrant) {
ImmutableSet.Builder<DesignatedContact> builder = new ImmutableSet.Builder<>();
if (includeRegistrant && registrantContact != null) {
builder.add(DesignatedContact.create(DesignatedContact.Type.REGISTRANT, registrantContact));
}
if (adminContact != null) {
builder.add(DesignatedContact.create(DesignatedContact.Type.ADMIN, adminContact));
}
if (billingContact != null) {
builder.add(DesignatedContact.create(DesignatedContact.Type.BILLING, billingContact));
}
if (techContact != null) {
builder.add(DesignatedContact.create(DesignatedContact.Type.TECH, techContact));
}
return builder.build();
}
public String getTld() { public String getTld() {
return tld; return tld;
} }
@ -764,7 +678,13 @@ public class DomainContent extends EppResource
if (includeRegistrant) { if (includeRegistrant) {
registrantContact = null; registrantContact = null;
} }
HashSet<DesignatedContact.Type> contactsDiscovered = new HashSet<DesignatedContact.Type>();
for (DesignatedContact contact : contacts) { for (DesignatedContact contact : contacts) {
checkArgument(
!contactsDiscovered.contains(contact.getType()),
"Duplicate contact type %s in designated contact set.",
contact.getType());
contactsDiscovered.add(contact.getType());
switch (contact.getType()) { switch (contact.getType()) {
case BILLING: case BILLING:
billingContact = contact.getContactKey(); billingContact = contact.getContactKey();
@ -793,24 +713,6 @@ public class DomainContent extends EppResource
+ " use DomainBase instead"); + " use DomainBase instead");
} }
/**
* 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;
}
Key<?> parent = key.getOfyKey().getParent();
if (parent == null || parent.getKind().equals("EntityGroupRoot")) {
return null;
}
return parent.getId();
}
/** Predicate to determine if a given {@link DesignatedContact} is the registrant. */ /** Predicate to determine if a given {@link DesignatedContact} is the registrant. */
static final Predicate<DesignatedContact> IS_REGISTRANT = static final Predicate<DesignatedContact> IS_REGISTRANT =
(DesignatedContact contact) -> DesignatedContact.Type.REGISTRANT.equals(contact.type); (DesignatedContact contact) -> DesignatedContact.Type.REGISTRANT.equals(contact.type);
@ -848,10 +750,6 @@ public class DomainContent extends EppResource
instance.autorenewEndTime = firstNonNull(getInstance().autorenewEndTime, END_OF_TIME); instance.autorenewEndTime = firstNonNull(getInstance().autorenewEndTime, END_OF_TIME);
checkArgumentNotNull(emptyToNull(instance.fullyQualifiedDomainName), "Missing domainName"); checkArgumentNotNull(emptyToNull(instance.fullyQualifiedDomainName), "Missing domainName");
if (instance.getRegistrant() == null
&& instance.allContacts.stream().anyMatch(IS_REGISTRANT)) {
throw new IllegalArgumentException("registrant is null but is in allContacts");
}
checkArgumentNotNull(instance.getRegistrant(), "Missing registrant"); checkArgumentNotNull(instance.getRegistrant(), "Missing registrant");
instance.tld = getTldFromDomainName(instance.fullyQualifiedDomainName); instance.tld = getTldFromDomainName(instance.fullyQualifiedDomainName);
@ -885,13 +783,6 @@ public class DomainContent extends EppResource
} }
public B setRegistrant(VKey<ContactResource> registrant) { public B setRegistrant(VKey<ContactResource> registrant) {
// Replace the registrant contact inside allContacts.
getInstance().allContacts =
union(
getInstance().getContacts(),
DesignatedContact.create(
DesignatedContact.Type.REGISTRANT, checkArgumentNotNull(registrant)));
// Set the registrant field specifically. // Set the registrant field specifically.
getInstance().registrantContact = registrant; getInstance().registrantContact = registrant;
return thisCastToDerived(); return thisCastToDerived();
@ -939,13 +830,6 @@ public class DomainContent extends EppResource
public B setContacts(ImmutableSet<DesignatedContact> contacts) { public B setContacts(ImmutableSet<DesignatedContact> contacts) {
checkArgument(contacts.stream().noneMatch(IS_REGISTRANT), "Registrant cannot be a contact"); checkArgument(contacts.stream().noneMatch(IS_REGISTRANT), "Registrant cannot be a contact");
// Replace the non-registrant contacts inside allContacts.
getInstance().allContacts =
Streams.concat(
nullToEmpty(getInstance().allContacts).stream().filter(IS_REGISTRANT),
contacts.stream())
.collect(toImmutableSet());
// Set the individual fields. // Set the individual fields.
getInstance().setContactFields(contacts, false); getInstance().setContactFields(contacts, false);
return thisCastToDerived(); return thisCastToDerived();
@ -992,19 +876,19 @@ public class DomainContent extends EppResource
public B setDeletePollMessage(VKey<PollMessage.OneTime> deletePollMessage) { public B setDeletePollMessage(VKey<PollMessage.OneTime> deletePollMessage) {
getInstance().deletePollMessage = deletePollMessage; getInstance().deletePollMessage = deletePollMessage;
getInstance().deletePollMessageHistoryId = getHistoryId(deletePollMessage);
return thisCastToDerived(); return thisCastToDerived();
} }
public B setAutorenewBillingEvent(VKey<BillingEvent.Recurring> autorenewBillingEvent) { public B setAutorenewBillingEvent(VKey<BillingEvent.Recurring> autorenewBillingEvent) {
getInstance().autorenewBillingEvent = autorenewBillingEvent; getInstance().autorenewBillingEvent = autorenewBillingEvent;
getInstance().autorenewBillingEventHistoryId = getHistoryId(autorenewBillingEvent);
return thisCastToDerived(); return thisCastToDerived();
} }
public B setAutorenewPollMessage(VKey<PollMessage.Autorenew> autorenewPollMessage) { public B setAutorenewPollMessage(
@Nullable VKey<PollMessage.Autorenew> autorenewPollMessage,
@Nullable Long autorenewPollMessageHistoryId) {
getInstance().autorenewPollMessage = autorenewPollMessage; getInstance().autorenewPollMessage = autorenewPollMessage;
getInstance().autorenewPollMessageHistoryId = getHistoryId(autorenewPollMessage); getInstance().autorenewPollMessageHistoryId = autorenewPollMessageHistoryId;
return thisCastToDerived(); return thisCastToDerived();
} }

View file

@ -326,23 +326,13 @@ public class DomainHistory extends HistoryEntry {
this.id = id; this.id = id;
} }
/** /** Returns the domain repository id. */
* Returns the domain repository id. public String getDomainRepoId() {
*
* <p>This method is private because it is only used by Hibernate.
*/
@SuppressWarnings("unused")
private String getDomainRepoId() {
return domainRepoId; return domainRepoId;
} }
/** /** Returns the history revision id. */
* Returns the history revision id. public long getId() {
*
* <p>This method is private because it is only used by Hibernate.
*/
@SuppressWarnings("unused")
private long getId() {
return id; return id;
} }

View file

@ -24,8 +24,6 @@ import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Recurring; import google.registry.model.billing.BillingEvent.Recurring;
import google.registry.model.domain.DomainHistory.DomainHistoryId; import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.domain.rgp.GracePeriodStatus; import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.persistence.BillingVKey.BillingEventVKey;
import google.registry.persistence.BillingVKey.BillingRecurrenceVKey;
import google.registry.persistence.VKey; import google.registry.persistence.VKey;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.persistence.Access; import javax.persistence.Access;
@ -78,8 +76,8 @@ public class GracePeriod extends GracePeriodBase {
instance.domainRepoId = checkArgumentNotNull(domainRepoId); instance.domainRepoId = checkArgumentNotNull(domainRepoId);
instance.expirationTime = checkArgumentNotNull(expirationTime); instance.expirationTime = checkArgumentNotNull(expirationTime);
instance.clientId = checkArgumentNotNull(registrarId); instance.clientId = checkArgumentNotNull(registrarId);
instance.billingEventOneTime = BillingEventVKey.create(billingEventOneTime); instance.billingEventOneTime = billingEventOneTime;
instance.billingEventRecurring = BillingRecurrenceVKey.create(billingEventRecurring); instance.billingEventRecurring = billingEventRecurring;
return instance; return instance;
} }
@ -126,8 +124,8 @@ public class GracePeriod extends GracePeriodBase {
history.domainRepoId, history.domainRepoId,
history.expirationTime, history.expirationTime,
history.clientId, history.clientId,
history.billingEventOneTime == null ? null : history.billingEventOneTime.createVKey(), history.billingEventOneTime,
history.billingEventRecurring == null ? null : history.billingEventRecurring.createVKey(), history.billingEventRecurring,
history.gracePeriodId); history.gracePeriodId);
} }

View file

@ -20,8 +20,6 @@ import google.registry.model.ImmutableObject;
import google.registry.model.UnsafeSerializable; import google.registry.model.UnsafeSerializable;
import google.registry.model.billing.BillingEvent; import google.registry.model.billing.BillingEvent;
import google.registry.model.domain.rgp.GracePeriodStatus; import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.persistence.BillingVKey.BillingEventVKey;
import google.registry.persistence.BillingVKey.BillingRecurrenceVKey;
import google.registry.persistence.VKey; import google.registry.persistence.VKey;
import javax.persistence.Access; import javax.persistence.Access;
import javax.persistence.AccessType; import javax.persistence.AccessType;
@ -66,7 +64,8 @@ public class GracePeriodBase extends ImmutableObject implements UnsafeSerializab
*/ */
// NB: Would @IgnoreSave(IfNull.class), but not allowed for @Embed collections. // NB: Would @IgnoreSave(IfNull.class), but not allowed for @Embed collections.
@Access(AccessType.FIELD) @Access(AccessType.FIELD)
BillingEventVKey billingEventOneTime = null; @Column(name = "billing_event_id")
VKey<BillingEvent.OneTime> billingEventOneTime = null;
/** /**
* The recurring billing event corresponding to the action that triggered this grace period, if * The recurring billing event corresponding to the action that triggered this grace period, if
@ -74,7 +73,8 @@ public class GracePeriodBase extends ImmutableObject implements UnsafeSerializab
*/ */
// NB: Would @IgnoreSave(IfNull.class), but not allowed for @Embed collections. // NB: Would @IgnoreSave(IfNull.class), but not allowed for @Embed collections.
@Access(AccessType.FIELD) @Access(AccessType.FIELD)
BillingRecurrenceVKey billingEventRecurring = null; @Column(name = "billing_recurrence_id")
VKey<BillingEvent.Recurring> billingEventRecurring = null;
public long getGracePeriodId() { public long getGracePeriodId() {
return gracePeriodId; return gracePeriodId;
@ -112,7 +112,7 @@ public class GracePeriodBase extends ImmutableObject implements UnsafeSerializab
* period is not AUTO_RENEW. * period is not AUTO_RENEW.
*/ */
public VKey<BillingEvent.OneTime> getOneTimeBillingEvent() { public VKey<BillingEvent.OneTime> getOneTimeBillingEvent() {
return billingEventOneTime == null ? null : billingEventOneTime.createVKey(); return billingEventOneTime;
} }
/** /**
@ -120,6 +120,6 @@ public class GracePeriodBase extends ImmutableObject implements UnsafeSerializab
* period is AUTO_RENEW. * period is AUTO_RENEW.
*/ */
public VKey<BillingEvent.Recurring> getRecurringBillingEvent() { public VKey<BillingEvent.Recurring> getRecurringBillingEvent() {
return billingEventRecurring == null ? null : billingEventRecurring.createVKey(); return billingEventRecurring;
} }
} }

View file

@ -85,6 +85,10 @@ public class HostHistory extends HistoryEntry implements UnsafeSerializable {
return super.getId(); return super.getId();
} }
public HostHistoryId getHostHistoryId() {
return new HostHistoryId(getHostRepoId(), getId());
}
/** /**
* The values of all the fields on the {@link HostBase} object after the action represented by * The values of all the fields on the {@link HostBase} object after the action represented by
* this history object was executed. * this history object was executed.
@ -147,8 +151,7 @@ public class HostHistory extends HistoryEntry implements UnsafeSerializable {
* *
* <p>This method is private because it is only used by Hibernate. * <p>This method is private because it is only used by Hibernate.
*/ */
@SuppressWarnings("unused") public String getHostRepoId() {
private String getHostRepoId() {
return hostRepoId; return hostRepoId;
} }
@ -157,8 +160,7 @@ public class HostHistory extends HistoryEntry implements UnsafeSerializable {
* *
* <p>This method is private because it is only used by Hibernate. * <p>This method is private because it is only used by Hibernate.
*/ */
@SuppressWarnings("unused") public long getId() {
private long getId() {
return id; return id;
} }

View file

@ -14,10 +14,8 @@
package google.registry.model.poll; package google.registry.model.poll;
import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.util.CollectionUtils.forceEmptyToNull; import static com.google.common.base.Preconditions.checkState;
import static google.registry.util.CollectionUtils.isNullOrEmpty;
import static google.registry.util.CollectionUtils.nullToEmpty;
import static google.registry.util.DateTimeUtils.END_OF_TIME; import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull; import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
@ -28,18 +26,22 @@ import com.googlecode.objectify.annotation.EntitySubclass;
import com.googlecode.objectify.annotation.Id; import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Ignore; import com.googlecode.objectify.annotation.Ignore;
import com.googlecode.objectify.annotation.Index; import com.googlecode.objectify.annotation.Index;
import com.googlecode.objectify.annotation.OnLoad;
import com.googlecode.objectify.annotation.Parent;
import google.registry.model.Buildable; import google.registry.model.Buildable;
import google.registry.model.EppResource; import google.registry.model.EppResource;
import google.registry.model.ImmutableObject; import google.registry.model.ImmutableObject;
import google.registry.model.UnsafeSerializable; import google.registry.model.UnsafeSerializable;
import google.registry.model.annotations.ExternalMessagingName; import google.registry.model.annotations.ExternalMessagingName;
import google.registry.model.annotations.ReportedOn; import google.registry.model.annotations.ReportedOn;
import google.registry.model.contact.ContactHistory;
import google.registry.model.contact.ContactHistory.ContactHistoryId;
import google.registry.model.contact.ContactResource; import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainBase; import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.domain.DomainRenewData; import google.registry.model.domain.DomainRenewData;
import google.registry.model.eppoutput.EppResponse.ResponseData; import google.registry.model.eppoutput.EppResponse.ResponseData;
import google.registry.model.host.HostHistory;
import google.registry.model.host.HostHistory.HostHistoryId;
import google.registry.model.host.HostResource; import google.registry.model.host.HostResource;
import google.registry.model.poll.PendingActionNotificationResponse.ContactPendingActionNotificationResponse; import google.registry.model.poll.PendingActionNotificationResponse.ContactPendingActionNotificationResponse;
import google.registry.model.poll.PendingActionNotificationResponse.DomainPendingActionNotificationResponse; import google.registry.model.poll.PendingActionNotificationResponse.DomainPendingActionNotificationResponse;
@ -51,7 +53,7 @@ import google.registry.model.transfer.TransferResponse.ContactTransferResponse;
import google.registry.model.transfer.TransferResponse.DomainTransferResponse; import google.registry.model.transfer.TransferResponse.DomainTransferResponse;
import google.registry.persistence.VKey; import google.registry.persistence.VKey;
import google.registry.persistence.WithLongVKey; import google.registry.persistence.WithLongVKey;
import java.util.List; import google.registry.util.NullIgnoringCollectionBuilder;
import java.util.Optional; import java.util.Optional;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.persistence.AttributeOverride; import javax.persistence.AttributeOverride;
@ -63,7 +65,6 @@ import javax.persistence.Embedded;
import javax.persistence.Inheritance; import javax.persistence.Inheritance;
import javax.persistence.InheritanceType; import javax.persistence.InheritanceType;
import javax.persistence.PostLoad; import javax.persistence.PostLoad;
import javax.persistence.Transient;
import org.joda.time.DateTime; import org.joda.time.DateTime;
/** /**
@ -100,14 +101,54 @@ import org.joda.time.DateTime;
public abstract class PollMessage extends ImmutableObject public abstract class PollMessage extends ImmutableObject
implements Buildable, TransferServerApproveEntity, UnsafeSerializable { implements Buildable, TransferServerApproveEntity, UnsafeSerializable {
/** Indicates the type of entity the poll message is for. */
public enum Type {
DOMAIN(1L, DomainBase.class),
CONTACT(2L, ContactResource.class),
HOST(3L, HostResource.class);
private final long id;
private final Class<?> clazz;
Type(long id, Class<?> clazz) {
this.id = id;
this.clazz = clazz;
}
/**
* Returns a numeric id for the enum, which is used as part of an externally published string
* key for the message.
*/
public long getId() {
return id;
}
/** Returns the class of the underlying resource for the poll message type. */
public Class<?> getResourceClass() {
return clazz;
}
/**
* Returns the type specified by the identifer, {@code Optional.empty()} if the id is out of
* range.
*/
public static Optional<Type> fromId(long id) {
for (Type val : values()) {
if (val.id == id) {
return Optional.of(val);
}
}
return Optional.empty();
}
}
/** Entity id. */ /** Entity id. */
@Id @Id
@javax.persistence.Id @javax.persistence.Id
@Column(name = "poll_message_id") @Column(name = "poll_message_id")
Long id; Long id;
@Parent @DoNotHydrate @Transient Key<? extends HistoryEntry> parent;
/** The registrar that this poll message will be delivered to. */ /** The registrar that this poll message will be delivered to. */
@Index @Index
@Column(name = "registrar_id", nullable = false) @Column(name = "registrar_id", nullable = false)
@ -122,6 +163,8 @@ public abstract class PollMessage extends ImmutableObject
@Column(name = "message") @Column(name = "message")
String msg; String msg;
// TODO(b/456803336): Replace these fields with {Domain,Contact,Host}HistoryId objects.
@Ignore String domainRepoId; @Ignore String domainRepoId;
@Ignore String contactRepoId; @Ignore String contactRepoId;
@ -134,10 +177,6 @@ public abstract class PollMessage extends ImmutableObject
@Ignore Long hostHistoryRevisionId; @Ignore Long hostHistoryRevisionId;
public Key<? extends HistoryEntry> getParentKey() {
return parent;
}
public Long getId() { public Long getId() {
return id; return id;
} }
@ -154,36 +193,59 @@ public abstract class PollMessage extends ImmutableObject
return msg; return msg;
} }
/**
* Returns the domain repo id.
*
* <p>This may only be used on a Domain poll event.
*/
public String getDomainRepoId() {
checkArgument(getType() == Type.DOMAIN);
return domainRepoId;
}
/**
* Returns the contact repo id.
*
* <p>This may only be used on a ContactResource poll event.
*/
public String getContactRepoId() {
checkArgument(getType() == Type.CONTACT);
return contactRepoId;
}
/**
* Returns the host repo id.
*
* <p>This may only be used on a HostResource poll event.
*/
public String getHostRepoId() {
checkArgument(getType() == Type.DOMAIN);
return hostRepoId;
}
/**
* Gets the name of the underlying resource that the PollMessage is for, regardless of the type of
* the resource.
*/
public String getResourceName() {
return domainRepoId != null
? domainRepoId
: (contactRepoId != null ? contactRepoId : hostRepoId);
}
/** Gets the underlying history revision id, regardless of the type of the resource. */
public Long getHistoryRevisionId() {
return domainHistoryRevisionId != null
? domainHistoryRevisionId
: (contactHistoryRevisionId != null ? contactHistoryRevisionId : hostHistoryRevisionId);
}
public Type getType() {
return domainRepoId != null ? Type.DOMAIN : (contactRepoId != null ? Type.CONTACT : Type.HOST);
}
public abstract ImmutableList<ResponseData> getResponseData(); public abstract ImmutableList<ResponseData> getResponseData();
@PostLoad
void postLoad() {
if (domainRepoId != null) {
parent =
Key.create(
Key.create(DomainBase.class, domainRepoId),
HistoryEntry.class,
domainHistoryRevisionId);
} else if (contactRepoId != null) {
parent =
Key.create(
Key.create(ContactResource.class, contactRepoId),
HistoryEntry.class,
contactHistoryRevisionId);
} else if (hostHistoryRevisionId != null) {
parent =
Key.create(
Key.create(HostResource.class, hostRepoId),
HistoryEntry.class,
hostHistoryRevisionId);
}
}
@OnLoad
void onLoad() {
setSqlForeignKeys(this);
}
@Override @Override
public abstract VKey<? extends PollMessage> createVKey(); public abstract VKey<? extends PollMessage> createVKey();
@ -234,46 +296,77 @@ public abstract class PollMessage extends ImmutableObject
return thisCastToDerived(); return thisCastToDerived();
} }
public B setParent(HistoryEntry parent) { public B setDomainHistoryId(DomainHistoryId historyId) {
getInstance().parent = Key.create(parent); getInstance().domainRepoId = historyId.getDomainRepoId();
getInstance().domainHistoryRevisionId = historyId.getId();
return thisCastToDerived(); return thisCastToDerived();
} }
public B setParentKey(Key<? extends HistoryEntry> parentKey) { public B setContactHistoryId(ContactHistoryId historyId) {
getInstance().parent = parentKey; getInstance().contactRepoId = historyId.getContactRepoId();
getInstance().contactHistoryRevisionId = historyId.getId();
return thisCastToDerived(); return thisCastToDerived();
} }
public B setHostHistoryId(HostHistoryId historyId) {
getInstance().hostRepoId = historyId.getHostRepoId();
getInstance().hostHistoryRevisionId = historyId.getId();
return thisCastToDerived();
}
public B setHistoryEntry(HistoryEntry history) {
// Set the appropriate field based on the history entry type.
if (history instanceof DomainHistory) {
return setDomainHistoryId(((DomainHistory) history).getDomainHistoryId());
} else if (history instanceof ContactHistory) {
return setContactHistoryId(((ContactHistory) history).getContactHistoryId());
} else if (history instanceof HostHistory) {
return setHostHistoryId(((HostHistory) history).getHostHistoryId());
}
return thisCastToDerived();
}
/**
* Given an array containing pairs of objects, verifies that both members of exactly one of the
* pairs is non-null.
*/
private boolean exactlyOnePairNonNull(Object... pairs) {
int count = 0;
checkArgument(pairs.length % 2 == 0, "Odd number of arguments provided.");
for (int i = 0; i < pairs.length; i += 2) {
// Add the number of non-null elements of each pair, after which the count should either be
// zero (a non-null pair hasn't been found yet) or two (exactly one non-null pair has been
// found).
count += (pairs[i] != null ? 1 : 0) + (pairs[i + 1] != null ? 1 : 0);
if (count != 0 && count != 2) {
return false;
}
}
// Verify that we've found a non-null pair.
return count == 2;
}
@Override @Override
public T build() { public T build() {
T instance = getInstance(); T instance = getInstance();
checkArgumentNotNull(instance.clientId, "clientId must be specified"); checkArgumentNotNull(instance.clientId, "clientId must be specified");
checkArgumentNotNull(instance.eventTime, "eventTime must be specified"); checkArgumentNotNull(instance.eventTime, "eventTime must be specified");
checkArgumentNotNull(instance.parent, "parent must be specified"); checkState(
checkArgumentNotNull(instance.parent.getParent(), "parent.getParent() must be specified"); exactlyOnePairNonNull(
setSqlForeignKeys(instance); instance.domainRepoId,
instance.domainHistoryRevisionId,
instance.contactRepoId,
instance.contactHistoryRevisionId,
instance.hostRepoId,
instance.hostHistoryRevisionId),
"the repo id and history revision id must be defined for exactly one of domain, "
+ "contact or host: "
+ instance);
return super.build(); return super.build();
} }
} }
private static void setSqlForeignKeys(PollMessage pollMessage) {
String grandparentKind = pollMessage.parent.getParent().getKind();
String repoId = pollMessage.parent.getParent().getName();
long historyRevisionId = pollMessage.parent.getId();
if (Key.getKind(DomainBase.class).equals(grandparentKind)) {
pollMessage.domainRepoId = repoId;
pollMessage.domainHistoryRevisionId = historyRevisionId;
} else if (Key.getKind(ContactResource.class).equals(grandparentKind)) {
pollMessage.contactRepoId = repoId;
pollMessage.contactHistoryRevisionId = historyRevisionId;
} else if (Key.getKind(HostResource.class).equals(grandparentKind)) {
pollMessage.hostRepoId = repoId;
pollMessage.hostHistoryRevisionId = historyRevisionId;
} else {
throw new IllegalArgumentException("Unknown grandparent kind: " + grandparentKind);
}
}
/** /**
* A one-time poll message. * A one-time poll message.
* *
@ -285,20 +378,6 @@ public abstract class PollMessage extends ImmutableObject
@WithLongVKey(compositeKey = true) @WithLongVKey(compositeKey = true)
public static class OneTime extends PollMessage { public static class OneTime extends PollMessage {
// Response data. Objectify cannot persist a base class type, so we must have a separate field
// to hold every possible derived type of ResponseData that we might store.
@Transient
List<ContactPendingActionNotificationResponse> contactPendingActionNotificationResponses;
@Transient List<ContactTransferResponse> contactTransferResponses;
@Transient @ImmutableObject.DoNotCompare
List<DomainPendingActionNotificationResponse> domainPendingActionNotificationResponses;
@Transient @ImmutableObject.DoNotCompare List<DomainTransferResponse> domainTransferResponses;
@Transient List<HostPendingActionNotificationResponse> hostPendingActionNotificationResponses;
@Ignore @Ignore
@Embedded @Embedded
@AttributeOverrides({ @AttributeOverrides({
@ -379,78 +458,38 @@ public abstract class PollMessage extends ImmutableObject
@Override @Override
public ImmutableList<ResponseData> getResponseData() { public ImmutableList<ResponseData> getResponseData() {
return new ImmutableList.Builder<ResponseData>() return NullIgnoringCollectionBuilder.create(new ImmutableList.Builder<ResponseData>())
.addAll(nullToEmpty(contactPendingActionNotificationResponses)) .add(pendingActionNotificationResponse)
.addAll(nullToEmpty(contactTransferResponses)) .add(transferResponse)
.addAll(nullToEmpty(domainPendingActionNotificationResponses)) .getBuilder()
.addAll(nullToEmpty(domainTransferResponses))
.addAll(nullToEmpty(hostPendingActionNotificationResponses))
.build(); .build();
} }
@Override
@OnLoad
void onLoad() {
super.onLoad();
// Take the Objectify-specific fields and map them to the SQL-specific fields, if applicable
if (!isNullOrEmpty(contactPendingActionNotificationResponses)) {
contactId = contactPendingActionNotificationResponses.get(0).getId().value;
pendingActionNotificationResponse = contactPendingActionNotificationResponses.get(0);
}
if (!isNullOrEmpty(hostPendingActionNotificationResponses)) {
hostId = hostPendingActionNotificationResponses.get(0).nameOrId.value;
pendingActionNotificationResponse = hostPendingActionNotificationResponses.get(0);
}
if (!isNullOrEmpty(contactTransferResponses)) {
contactId = contactTransferResponses.get(0).getContactId();
transferResponse = contactTransferResponses.get(0);
}
if (!isNullOrEmpty(domainPendingActionNotificationResponses)) {
pendingActionNotificationResponse = domainPendingActionNotificationResponses.get(0);
fullyQualifiedDomainName = pendingActionNotificationResponse.nameOrId.value;
}
if (!isNullOrEmpty(domainTransferResponses)) {
fullyQualifiedDomainName = domainTransferResponses.get(0).getFullyQualifiedDomainName();
transferResponse = domainTransferResponses.get(0);
extendedRegistrationExpirationTime =
domainTransferResponses.get(0).getExtendedRegistrationExpirationTime();
}
}
@Override
@PostLoad @PostLoad
void postLoad() { void postLoad() {
super.postLoad();
// Take the SQL-specific fields and map them to the Objectify-specific fields, if applicable
if (pendingActionNotificationResponse != null) { if (pendingActionNotificationResponse != null) {
// Promote the pending action notification response to its specialized type.
if (contactId != null) { if (contactId != null) {
ContactPendingActionNotificationResponse contactPendingResponse = pendingActionNotificationResponse =
ContactPendingActionNotificationResponse.create( ContactPendingActionNotificationResponse.create(
pendingActionNotificationResponse.nameOrId.value, pendingActionNotificationResponse.nameOrId.value,
pendingActionNotificationResponse.getActionResult(), pendingActionNotificationResponse.getActionResult(),
pendingActionNotificationResponse.getTrid(), pendingActionNotificationResponse.getTrid(),
pendingActionNotificationResponse.processedDate); pendingActionNotificationResponse.processedDate);
pendingActionNotificationResponse = contactPendingResponse;
contactPendingActionNotificationResponses = ImmutableList.of(contactPendingResponse);
} else if (fullyQualifiedDomainName != null) { } else if (fullyQualifiedDomainName != null) {
DomainPendingActionNotificationResponse domainPendingResponse = pendingActionNotificationResponse =
DomainPendingActionNotificationResponse.create( DomainPendingActionNotificationResponse.create(
pendingActionNotificationResponse.nameOrId.value, pendingActionNotificationResponse.nameOrId.value,
pendingActionNotificationResponse.getActionResult(), pendingActionNotificationResponse.getActionResult(),
pendingActionNotificationResponse.getTrid(), pendingActionNotificationResponse.getTrid(),
pendingActionNotificationResponse.processedDate); pendingActionNotificationResponse.processedDate);
pendingActionNotificationResponse = domainPendingResponse;
domainPendingActionNotificationResponses = ImmutableList.of(domainPendingResponse);
} else if (hostId != null) { } else if (hostId != null) {
HostPendingActionNotificationResponse hostPendingActionNotificationResponse = pendingActionNotificationResponse =
HostPendingActionNotificationResponse.create( HostPendingActionNotificationResponse.create(
pendingActionNotificationResponse.nameOrId.value, pendingActionNotificationResponse.nameOrId.value,
pendingActionNotificationResponse.getActionResult(), pendingActionNotificationResponse.getActionResult(),
pendingActionNotificationResponse.getTrid(), pendingActionNotificationResponse.getTrid(),
pendingActionNotificationResponse.processedDate); pendingActionNotificationResponse.processedDate);
pendingActionNotificationResponse = hostPendingActionNotificationResponse;
hostPendingActionNotificationResponses =
ImmutableList.of(hostPendingActionNotificationResponse);
} }
} }
if (transferResponse != null) { if (transferResponse != null) {
@ -467,7 +506,6 @@ public abstract class PollMessage extends ImmutableObject
.setPendingTransferExpirationTime( .setPendingTransferExpirationTime(
transferResponse.getPendingTransferExpirationTime()) transferResponse.getPendingTransferExpirationTime())
.build(); .build();
contactTransferResponses = ImmutableList.of((ContactTransferResponse) transferResponse);
} else if (fullyQualifiedDomainName != null) { } else if (fullyQualifiedDomainName != null) {
transferResponse = transferResponse =
new DomainTransferResponse.Builder() new DomainTransferResponse.Builder()
@ -480,7 +518,6 @@ public abstract class PollMessage extends ImmutableObject
transferResponse.getPendingTransferExpirationTime()) transferResponse.getPendingTransferExpirationTime())
.setExtendedRegistrationExpirationTime(extendedRegistrationExpirationTime) .setExtendedRegistrationExpirationTime(extendedRegistrationExpirationTime)
.build(); .build();
domainTransferResponses = ImmutableList.of((DomainTransferResponse) transferResponse);
} }
} }
} }
@ -497,66 +534,52 @@ public abstract class PollMessage extends ImmutableObject
public Builder setResponseData(ImmutableList<? extends ResponseData> responseData) { public Builder setResponseData(ImmutableList<? extends ResponseData> responseData) {
OneTime instance = getInstance(); OneTime instance = getInstance();
instance.contactPendingActionNotificationResponses = // Note: In its current form, the code will basically just ignore everything but the first
forceEmptyToNull( // PendingActionNotificationResponse and TransferResponse in responseData, and will override
responseData.stream() // any identifier fields (e.g. contactId, fullyQualifiedDomainName) obtained from the
.filter(ContactPendingActionNotificationResponse.class::isInstance) // PendingActionNotificationResponse if a TransferResponse is found with different values
.map(ContactPendingActionNotificationResponse.class::cast) // for those fields. It is not clear what the constraints should be on this data or
.collect(toImmutableList())); // whether we should enforce them here, though historically we have not, so the current
// implementation doesn't.
instance.contactTransferResponses = // Extract the first PendingActionNotificationResponse element from the list if there is
forceEmptyToNull( // one.
responseData.stream() instance.pendingActionNotificationResponse =
.filter(ContactTransferResponse.class::isInstance) responseData.stream()
.map(ContactTransferResponse.class::cast) .filter(PendingActionNotificationResponse.class::isInstance)
.collect(toImmutableList())); .map(PendingActionNotificationResponse.class::cast)
.findFirst()
.orElse(null);
instance.domainPendingActionNotificationResponses = // Set identifier fields based on the type of the notification response.
forceEmptyToNull( if (instance.pendingActionNotificationResponse
responseData.stream() instanceof ContactPendingActionNotificationResponse) {
.filter(DomainPendingActionNotificationResponse.class::isInstance) instance.contactId = instance.pendingActionNotificationResponse.nameOrId.value;
.map(DomainPendingActionNotificationResponse.class::cast) } else if (instance.pendingActionNotificationResponse
.collect(toImmutableList())); instanceof DomainPendingActionNotificationResponse) {
instance.domainTransferResponses =
forceEmptyToNull(
responseData.stream()
.filter(DomainTransferResponse.class::isInstance)
.map(DomainTransferResponse.class::cast)
.collect(toImmutableList()));
instance.hostPendingActionNotificationResponses =
forceEmptyToNull(
responseData.stream()
.filter(HostPendingActionNotificationResponse.class::isInstance)
.map(HostPendingActionNotificationResponse.class::cast)
.collect(toImmutableList()));
// Set the generic pending-action field as appropriate
if (instance.contactPendingActionNotificationResponses != null) {
instance.pendingActionNotificationResponse =
instance.contactPendingActionNotificationResponses.get(0);
instance.contactId =
instance.contactPendingActionNotificationResponses.get(0).nameOrId.value;
} else if (instance.domainPendingActionNotificationResponses != null) {
instance.pendingActionNotificationResponse =
instance.domainPendingActionNotificationResponses.get(0);
instance.fullyQualifiedDomainName = instance.fullyQualifiedDomainName =
instance.domainPendingActionNotificationResponses.get(0).nameOrId.value; instance.pendingActionNotificationResponse.nameOrId.value;
} else if (instance.hostPendingActionNotificationResponses != null) { } else if (instance.pendingActionNotificationResponse
instance.pendingActionNotificationResponse = instanceof HostPendingActionNotificationResponse) {
instance.hostPendingActionNotificationResponses.get(0); instance.hostId = instance.pendingActionNotificationResponse.nameOrId.value;
instance.hostId = instance.hostPendingActionNotificationResponses.get(0).nameOrId.value;
} }
// Set the generic transfer response field as appropriate
if (instance.contactTransferResponses != null) { // Extract the first TransferResponse from the list.
instance.contactId = getInstance().contactTransferResponses.get(0).getContactId(); instance.transferResponse =
instance.transferResponse = getInstance().contactTransferResponses.get(0); responseData.stream()
} else if (instance.domainTransferResponses != null) { .filter(TransferResponse.class::isInstance)
instance.fullyQualifiedDomainName = .map(TransferResponse.class::cast)
instance.domainTransferResponses.get(0).getFullyQualifiedDomainName(); .findFirst()
instance.transferResponse = getInstance().domainTransferResponses.get(0); .orElse(null);
// Set the identifier according to the TransferResponse type.
if (instance.transferResponse instanceof ContactTransferResponse) {
instance.contactId = ((ContactTransferResponse) instance.transferResponse).getContactId();
} else if (instance.transferResponse instanceof DomainTransferResponse) {
DomainTransferResponse response = (DomainTransferResponse) instance.transferResponse;
instance.fullyQualifiedDomainName = response.getFullyQualifiedDomainName();
instance.extendedRegistrationExpirationTime = instance.extendedRegistrationExpirationTime =
instance.domainTransferResponses.get(0).getExtendedRegistrationExpirationTime(); response.getExtendedRegistrationExpirationTime();
} }
return this; return this;
} }

View file

@ -14,19 +14,12 @@
package google.registry.model.poll; package google.registry.model.poll;
import static com.google.common.collect.ImmutableMap.toImmutableMap;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableMap;
import com.googlecode.objectify.Key; import com.googlecode.objectify.Key;
import google.registry.model.EppResource;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainBase;
import google.registry.model.host.HostResource;
import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry;
import google.registry.persistence.VKey; import google.registry.persistence.VKey;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* A converter between external key strings for {@link PollMessage}s (i.e. what registrars use to * A converter between external key strings for {@link PollMessage}s (i.e. what registrars use to
@ -50,28 +43,13 @@ public class PollMessageExternalKeyConverter {
/** An exception thrown when an external key cannot be parsed. */ /** An exception thrown when an external key cannot be parsed. */
public static class PollMessageExternalKeyParseException extends RuntimeException {} public static class PollMessageExternalKeyParseException extends RuntimeException {}
/** Maps that detail the correspondence between EppResource classes and external IDs. */
private static final ImmutableMap<Long, Class<? extends EppResource>> ID_TO_CLASS_MAP =
ImmutableMap.of(
1L, DomainBase.class,
2L, ContactResource.class,
3L, HostResource.class);
private static final ImmutableMap<String, Long> KEY_KIND_TO_ID_MAP =
ID_TO_CLASS_MAP.entrySet().stream()
.collect(toImmutableMap(entry -> entry.getValue().getSimpleName(), Map.Entry::getKey));
/** Returns an external poll message ID for the given poll message. */ /** Returns an external poll message ID for the given poll message. */
public static String makePollMessageExternalId(PollMessage pollMessage) { public static String makePollMessageExternalId(PollMessage pollMessage) {
@SuppressWarnings("unchecked")
Key<EppResource> ancestorResource =
(Key<EppResource>) (Key<?>) pollMessage.getParentKey().getParent();
long externalKeyClassId = KEY_KIND_TO_ID_MAP.get(ancestorResource.getKind());
return String.format( return String.format(
"%d-%s-%d-%d-%d", "%d-%s-%d-%d-%d",
externalKeyClassId, pollMessage.getType().getId(),
ancestorResource.getName(), pollMessage.getResourceName(),
pollMessage.getParentKey().getId(), pollMessage.getHistoryRevisionId(),
pollMessage.getId(), pollMessage.getId(),
pollMessage.getEventTime().getYear()); pollMessage.getEventTime().getYear());
} }
@ -92,10 +70,10 @@ public class PollMessageExternalKeyConverter {
throw new PollMessageExternalKeyParseException(); throw new PollMessageExternalKeyParseException();
} }
try { try {
Class<?> resourceClazz = ID_TO_CLASS_MAP.get(Long.parseLong(idComponents.get(0))); Class<?> resourceClazz =
if (resourceClazz == null) { PollMessage.Type.fromId(Long.parseLong(idComponents.get(0)))
throw new PollMessageExternalKeyParseException(); .orElseThrow(() -> new PollMessageExternalKeyParseException())
} .getResourceClass();
return VKey.from( return VKey.from(
Key.create( Key.create(
Key.create( Key.create(
@ -115,4 +93,3 @@ public class PollMessageExternalKeyConverter {
private PollMessageExternalKeyConverter() {} private PollMessageExternalKeyConverter() {}
} }

View file

@ -14,25 +14,20 @@
package google.registry.model.transfer; package google.registry.model.transfer;
import static google.registry.util.CollectionUtils.forceEmptyToNull;
import static google.registry.util.CollectionUtils.isNullOrEmpty; import static google.registry.util.CollectionUtils.isNullOrEmpty;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.AlsoLoad;
import com.googlecode.objectify.annotation.Embed; import com.googlecode.objectify.annotation.Embed;
import com.googlecode.objectify.annotation.Ignore; import com.googlecode.objectify.annotation.Ignore;
import com.googlecode.objectify.annotation.IgnoreSave; import com.googlecode.objectify.annotation.IgnoreSave;
import com.googlecode.objectify.annotation.OnLoad;
import com.googlecode.objectify.annotation.Unindex; import com.googlecode.objectify.annotation.Unindex;
import com.googlecode.objectify.condition.IfNull; import com.googlecode.objectify.condition.IfNull;
import google.registry.model.billing.BillingEvent; import google.registry.model.billing.BillingEvent;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Period; import google.registry.model.domain.Period;
import google.registry.model.domain.Period.Unit; import google.registry.model.domain.Period.Unit;
import google.registry.model.poll.PollMessage; import google.registry.model.poll.PollMessage;
import google.registry.persistence.VKey; import google.registry.persistence.VKey;
import google.registry.util.NullIgnoringCollectionBuilder;
import java.util.Set; import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.persistence.AttributeOverride; import javax.persistence.AttributeOverride;
@ -40,7 +35,6 @@ import javax.persistence.AttributeOverrides;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Embeddable; import javax.persistence.Embeddable;
import javax.persistence.Embedded; import javax.persistence.Embedded;
import javax.persistence.PostLoad;
import org.joda.time.DateTime; import org.joda.time.DateTime;
/** Transfer data for domain. */ /** Transfer data for domain. */
@ -85,10 +79,6 @@ public class DomainTransferData extends TransferData<DomainTransferData.Builder>
@Column(name = "transfer_billing_cancellation_id") @Column(name = "transfer_billing_cancellation_id")
public VKey<BillingEvent.Cancellation> billingCancellationId; public VKey<BillingEvent.Cancellation> billingCancellationId;
@Ignore
@Column(name = "transfer_billing_cancellation_history_id")
Long billingCancellationHistoryId;
/** /**
* The regular one-time billing event that will be charged for a server-approved transfer. * The regular one-time billing event that will be charged for a server-approved transfer.
* *
@ -99,10 +89,6 @@ public class DomainTransferData extends TransferData<DomainTransferData.Builder>
@Column(name = "transfer_billing_event_id") @Column(name = "transfer_billing_event_id")
VKey<BillingEvent.OneTime> serverApproveBillingEvent; 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. * The autorenew billing event that should be associated with this resource after the transfer.
* *
@ -113,10 +99,6 @@ public class DomainTransferData extends TransferData<DomainTransferData.Builder>
@Column(name = "transfer_billing_recurrence_id") @Column(name = "transfer_billing_recurrence_id")
VKey<BillingEvent.Recurring> serverApproveAutorenewEvent; 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. * The autorenew poll message that should be associated with this resource after the transfer.
* *
@ -127,6 +109,10 @@ public class DomainTransferData extends TransferData<DomainTransferData.Builder>
@Column(name = "transfer_autorenew_poll_message_id") @Column(name = "transfer_autorenew_poll_message_id")
VKey<PollMessage.Autorenew> serverApproveAutorenewPollMessage; VKey<PollMessage.Autorenew> serverApproveAutorenewPollMessage;
/**
* Autorenew history, which we need to preserve because it's often used in contexts where we
* haven't loaded the autorenew object.
*/
@Ignore @Ignore
@Column(name = "transfer_autorenew_poll_message_history_id") @Column(name = "transfer_autorenew_poll_message_history_id")
Long serverApproveAutorenewPollMessageHistoryId; Long serverApproveAutorenewPollMessageHistoryId;
@ -136,36 +122,6 @@ public class DomainTransferData extends TransferData<DomainTransferData.Builder>
return super.copyConstantFieldsToBuilder().setTransferPeriod(this.transferPeriod); 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);
billingCancellationId =
DomainBase.restoreOfyFrom(rootKey, billingCancellationId, billingCancellationHistoryId);
// Reconstruct server approve entities. We currently have to call postLoad() a _second_ time
// if any of the billing objects have been reconstituted, as they are part of that set.
// TODO(b/183010623): Normalize the approaches to VKey reconstitution for the TransferData
// hierarchy (the logic currently lives either in PostLoad or here, depending on the key).
if (billingCancellationId != null
|| serverApproveBillingEvent != null
|| serverApproveAutorenewEvent != null) {
serverApproveEntities = null;
postLoad();
}
}
/** /**
* Fix the VKey "kind" for the PollMessage keys. * Fix the VKey "kind" for the PollMessage keys.
* *
@ -176,30 +132,6 @@ public class DomainTransferData extends TransferData<DomainTransferData.Builder>
PollMessage.Autorenew.convertVKey(serverApproveAutorenewPollMessage); PollMessage.Autorenew.convertVKey(serverApproveAutorenewPollMessage);
} }
@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);
}
@SuppressWarnings("unused") // For Hibernate.
private void billingCancellationHistoryId(
@AlsoLoad("billingCancellationHistoryId") VKey<BillingEvent.Cancellation> val) {
billingCancellationHistoryId = DomainBase.getHistoryId(val);
}
public Period getTransferPeriod() { public Period getTransferPeriod() {
return transferPeriod; return transferPeriod;
} }
@ -214,64 +146,32 @@ public class DomainTransferData extends TransferData<DomainTransferData.Builder>
return serverApproveBillingEvent; return serverApproveBillingEvent;
} }
@VisibleForTesting
@Nullable
public Long getServerApproveBillingEventHistoryId() {
return serverApproveBillingEventHistoryId;
}
@Nullable @Nullable
public VKey<BillingEvent.Recurring> getServerApproveAutorenewEvent() { public VKey<BillingEvent.Recurring> getServerApproveAutorenewEvent() {
return serverApproveAutorenewEvent; return serverApproveAutorenewEvent;
} }
@VisibleForTesting
@Nullable
public Long getServerApproveAutorenewEventHistoryId() {
return serverApproveAutorenewEventHistoryId;
}
@Nullable @Nullable
public VKey<PollMessage.Autorenew> getServerApproveAutorenewPollMessage() { public VKey<PollMessage.Autorenew> getServerApproveAutorenewPollMessage() {
return serverApproveAutorenewPollMessage; return serverApproveAutorenewPollMessage;
} }
@VisibleForTesting
@Nullable @Nullable
public Long getServerApproveAutorenewPollMessageHistoryId() { public Long getServerApproveAutorenewPollMessageHistoryId() {
return serverApproveAutorenewPollMessageHistoryId; return serverApproveAutorenewPollMessageHistoryId;
} }
@OnLoad
@Override @Override
void onLoad( public ImmutableSet<VKey<? extends TransferServerApproveEntity>> getServerApproveEntities() {
@AlsoLoad("serverApproveEntities") ImmutableSet.Builder<VKey<? extends TransferServerApproveEntity>> builder =
Set<VKey<? extends TransferServerApproveEntity>> serverApproveEntities) {
super.onLoad(serverApproveEntities);
mapBillingCancellationEntityToField(serverApproveEntities, this);
}
@PostLoad
@Override
void postLoad() {
super.postLoad();
// The superclass's serverApproveEntities should include the billing events if present
ImmutableSet.Builder<VKey<? extends TransferServerApproveEntity>> serverApproveEntitiesBuilder =
new ImmutableSet.Builder<>(); new ImmutableSet.Builder<>();
if (serverApproveEntities != null) { builder.addAll(super.getServerApproveEntities());
serverApproveEntitiesBuilder.addAll(serverApproveEntities); return NullIgnoringCollectionBuilder.create(builder)
} .add(serverApproveBillingEvent)
if (serverApproveBillingEvent != null) { .add(serverApproveAutorenewEvent)
serverApproveEntitiesBuilder.add(serverApproveBillingEvent); .add(billingCancellationId)
} .getBuilder()
if (serverApproveAutorenewEvent != null) { .build();
serverApproveEntitiesBuilder.add(serverApproveAutorenewEvent);
}
if (billingCancellationId != null) {
serverApproveEntitiesBuilder.add(billingCancellationId);
}
serverApproveEntities = forceEmptyToNull(serverApproveEntitiesBuilder.build());
hashCode = null; // reset the hash code since we may have changed the entities
} }
@Override @Override
@ -291,7 +191,6 @@ public class DomainTransferData extends TransferData<DomainTransferData.Builder>
DomainTransferData domainTransferData) { DomainTransferData domainTransferData) {
if (isNullOrEmpty(serverApproveEntities)) { if (isNullOrEmpty(serverApproveEntities)) {
domainTransferData.billingCancellationId = null; domainTransferData.billingCancellationId = null;
domainTransferData.billingCancellationHistoryId = null;
} else { } else {
domainTransferData.billingCancellationId = domainTransferData.billingCancellationId =
(VKey<BillingEvent.Cancellation>) (VKey<BillingEvent.Cancellation>)
@ -299,10 +198,6 @@ public class DomainTransferData extends TransferData<DomainTransferData.Builder>
.filter(k -> k.getKind().equals(BillingEvent.Cancellation.class)) .filter(k -> k.getKind().equals(BillingEvent.Cancellation.class))
.findFirst() .findFirst()
.orElse(null); .orElse(null);
domainTransferData.billingCancellationHistoryId =
domainTransferData.billingCancellationId != null
? DomainBase.getHistoryId(domainTransferData.billingCancellationId)
: null;
} }
} }
@ -315,12 +210,6 @@ public class DomainTransferData extends TransferData<DomainTransferData.Builder>
super(instance); super(instance);
} }
@Override
public DomainTransferData build() {
mapBillingCancellationEntityToField(getInstance().serverApproveEntities, getInstance());
return super.build();
}
public Builder setTransferPeriod(Period transferPeriod) { public Builder setTransferPeriod(Period transferPeriod) {
getInstance().transferPeriod = transferPeriod; getInstance().transferPeriod = transferPeriod;
return this; return this;
@ -335,24 +224,28 @@ public class DomainTransferData extends TransferData<DomainTransferData.Builder>
public Builder setServerApproveBillingEvent( public Builder setServerApproveBillingEvent(
VKey<BillingEvent.OneTime> serverApproveBillingEvent) { VKey<BillingEvent.OneTime> serverApproveBillingEvent) {
getInstance().serverApproveBillingEvent = serverApproveBillingEvent; getInstance().serverApproveBillingEvent = serverApproveBillingEvent;
getInstance().serverApproveBillingEventHistoryId =
DomainBase.getHistoryId(serverApproveBillingEvent);
return this; return this;
} }
public Builder setServerApproveAutorenewEvent( public Builder setServerApproveAutorenewEvent(
VKey<BillingEvent.Recurring> serverApproveAutorenewEvent) { VKey<BillingEvent.Recurring> serverApproveAutorenewEvent) {
getInstance().serverApproveAutorenewEvent = serverApproveAutorenewEvent; getInstance().serverApproveAutorenewEvent = serverApproveAutorenewEvent;
getInstance().serverApproveAutorenewEventHistoryId =
DomainBase.getHistoryId(serverApproveAutorenewEvent);
return this; return this;
} }
public Builder setServerApproveAutorenewPollMessage( public Builder setServerApproveAutorenewPollMessage(
VKey<PollMessage.Autorenew> serverApproveAutorenewPollMessage) { VKey<PollMessage.Autorenew> serverApproveAutorenewPollMessage) {
getInstance().serverApproveAutorenewPollMessage = serverApproveAutorenewPollMessage; getInstance().serverApproveAutorenewPollMessage = serverApproveAutorenewPollMessage;
getInstance().serverApproveAutorenewPollMessageHistoryId = return this;
DomainBase.getHistoryId(serverApproveAutorenewPollMessage); }
@Override
public Builder setServerApproveEntities(
String repoId,
Long historyId,
ImmutableSet<VKey<? extends TransferServerApproveEntity>> serverApproveEntities) {
super.setServerApproveEntities(repoId, historyId, serverApproveEntities);
mapBillingCancellationEntityToField(serverApproveEntities, getInstance());
return this; return this;
} }
} }

View file

@ -14,26 +14,20 @@
package google.registry.model.transfer; package google.registry.model.transfer;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableList.toImmutableList;
import static google.registry.util.CollectionUtils.isNullOrEmpty; import static google.registry.util.CollectionUtils.isNullOrEmpty;
import static google.registry.util.CollectionUtils.nullToEmpty; import static google.registry.util.CollectionUtils.nullToEmpty;
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.AlsoLoad;
import com.googlecode.objectify.annotation.Ignore; import com.googlecode.objectify.annotation.Ignore;
import com.googlecode.objectify.annotation.IgnoreSave;
import com.googlecode.objectify.condition.IfNull;
import google.registry.model.Buildable; import google.registry.model.Buildable;
import google.registry.model.EppResource; import google.registry.model.EppResource;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainBase;
import google.registry.model.eppcommon.Trid; import google.registry.model.eppcommon.Trid;
import google.registry.model.poll.PollMessage; import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry;
import google.registry.persistence.VKey; import google.registry.persistence.VKey;
import google.registry.util.NullIgnoringCollectionBuilder;
import google.registry.util.TypeUtils.TypeInstantiator; import google.registry.util.TypeUtils.TypeInstantiator;
import java.util.Set; import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -42,8 +36,6 @@ import javax.persistence.AttributeOverrides;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Embedded; import javax.persistence.Embedded;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
import javax.persistence.PostLoad;
import javax.persistence.Transient;
/** /**
* Common transfer data for {@link EppResource} types. Only applies to domains and contacts; hosts * Common transfer data for {@link EppResource} types. Only applies to domains and contacts; hosts
@ -66,20 +58,6 @@ public abstract class TransferData<
}) })
Trid transferRequestTrid; Trid transferRequestTrid;
/**
* The billing event and poll messages associated with a server-approved transfer.
*
* <p>This field should be null if there is not currently a pending transfer or if the object
* being transferred is not a domain. If there is a pending transfer for a domain there should be
* a number of poll messages and billing events for both the gaining and losing registrars. If the
* pending transfer is explicitly approved, rejected or cancelled, the referenced entities should
* be deleted.
*/
@Transient
@DoNotCompare
@IgnoreSave(IfNull.class)
Set<VKey<? extends TransferServerApproveEntity>> serverApproveEntities;
@Ignore @Ignore
@Column(name = "transfer_repo_id") @Column(name = "transfer_repo_id")
String repoId; String repoId;
@ -89,11 +67,7 @@ public abstract class TransferData<
Long historyEntryId; Long historyEntryId;
// The pollMessageId1 and pollMessageId2 are used to store the IDs for gaining and losing poll // The pollMessageId1 and pollMessageId2 are used to store the IDs for gaining and losing poll
// messages in Cloud SQL, and they are added to replace the VKeys in serverApproveEntities. // messages in Cloud SQL.
// Although we can distinguish which is which when we construct the TransferData instance from
// the transfer request flow, when the instance is loaded from Datastore, we cannot make this
// distinction because they are just VKeys. Also, the only way we use serverApproveEntities is to
// just delete all the entities referenced by the VKeys, so we don't need to make the distinction.
// //
// In addition, there may be a third poll message for the autorenew poll message on domain // In addition, there may be a third poll message for the autorenew poll message on domain
// transfer if applicable. // transfer if applicable.
@ -111,13 +85,23 @@ public abstract class TransferData<
public abstract boolean isEmpty(); public abstract boolean isEmpty();
public Long getHistoryEntryId() {
return historyEntryId;
}
@Nullable @Nullable
public Trid getTransferRequestTrid() { public Trid getTransferRequestTrid() {
return transferRequestTrid; return transferRequestTrid;
} }
public ImmutableSet<VKey<? extends TransferServerApproveEntity>> getServerApproveEntities() { public ImmutableSet<VKey<? extends TransferServerApproveEntity>> getServerApproveEntities() {
return nullToEmptyImmutableCopy(serverApproveEntities); return NullIgnoringCollectionBuilder.create(
new ImmutableSet.Builder<VKey<? extends TransferServerApproveEntity>>())
.add(pollMessageId1 != null ? VKey.createSql(PollMessage.class, pollMessageId1) : null)
.add(pollMessageId2 != null ? VKey.createSql(PollMessage.class, pollMessageId2) : null)
.add(pollMessageId3 != null ? VKey.createSql(PollMessage.class, pollMessageId3) : null)
.getBuilder()
.build();
} }
@Override @Override
@ -147,67 +131,16 @@ public abstract class TransferData<
return newBuilder; return newBuilder;
} }
void onLoad(
@AlsoLoad("serverApproveEntities")
Set<VKey<? extends TransferServerApproveEntity>> serverApproveEntities) {
mapServerApproveEntitiesToFields(serverApproveEntities, this);
}
@PostLoad
void postLoad() {
mapFieldsToServerApproveEntities();
}
/**
* Reconstructs serverApproveEntities set from the individual fields, e.g. repoId, historyEntryId,
* pollMessageId1.
*/
void mapFieldsToServerApproveEntities() {
if (repoId == null) {
return;
}
Key<? extends EppResource> eppKey;
if (getClass().equals(DomainTransferData.class)) {
eppKey = Key.create(DomainBase.class, repoId);
} else {
eppKey = Key.create(ContactResource.class, repoId);
}
Key<HistoryEntry> historyEntryKey = Key.create(eppKey, HistoryEntry.class, historyEntryId);
ImmutableSet.Builder<VKey<? extends TransferServerApproveEntity>> entityKeysBuilder =
new ImmutableSet.Builder<>();
if (pollMessageId1 != null) {
Key<PollMessage> ofyKey = Key.create(historyEntryKey, PollMessage.class, pollMessageId1);
entityKeysBuilder.add(PollMessage.createVKey(ofyKey));
}
if (pollMessageId2 != null) {
Key<PollMessage> ofyKey = Key.create(historyEntryKey, PollMessage.class, pollMessageId2);
entityKeysBuilder.add(PollMessage.createVKey(ofyKey));
}
if (pollMessageId3 != null) {
Key<PollMessage> ofyKey = Key.create(historyEntryKey, PollMessage.class, pollMessageId3);
entityKeysBuilder.add(PollMessage.createVKey(ofyKey));
}
serverApproveEntities = entityKeysBuilder.build();
}
/** Maps serverApproveEntities set to the individual fields. */ /** Maps serverApproveEntities set to the individual fields. */
static void mapServerApproveEntitiesToFields( static void mapServerApproveEntitiesToFields(
Set<VKey<? extends TransferServerApproveEntity>> serverApproveEntities, Set<VKey<? extends TransferServerApproveEntity>> serverApproveEntities,
TransferData transferData) { TransferData transferData) {
if (isNullOrEmpty(serverApproveEntities)) { if (isNullOrEmpty(serverApproveEntities)) {
transferData.historyEntryId = null;
transferData.repoId = null;
transferData.pollMessageId1 = null; transferData.pollMessageId1 = null;
transferData.pollMessageId2 = null; transferData.pollMessageId2 = null;
transferData.pollMessageId3 = null; transferData.pollMessageId3 = null;
return; return;
} }
// Each element in serverApproveEntities should have the exact same Key<HistoryEntry> as its
// parent. So, we can use any to set historyEntryId and repoId.
Key<?> key = serverApproveEntities.iterator().next().getOfyKey();
transferData.historyEntryId = key.getParent().getId();
transferData.repoId = key.getParent().getParent().getName();
ImmutableList<Long> sortedPollMessageIds = getSortedPollMessageIds(serverApproveEntities); ImmutableList<Long> sortedPollMessageIds = getSortedPollMessageIds(serverApproveEntities);
if (sortedPollMessageIds.size() >= 1) { if (sortedPollMessageIds.size() >= 1) {
transferData.pollMessageId1 = sortedPollMessageIds.get(0); transferData.pollMessageId1 = sortedPollMessageIds.get(0);
@ -250,14 +183,21 @@ public abstract class TransferData<
} }
public B setServerApproveEntities( public B setServerApproveEntities(
String repoId,
Long historyId,
ImmutableSet<VKey<? extends TransferServerApproveEntity>> serverApproveEntities) { ImmutableSet<VKey<? extends TransferServerApproveEntity>> serverApproveEntities) {
getInstance().serverApproveEntities = serverApproveEntities; getInstance().repoId = repoId;
getInstance().historyEntryId = historyId;
mapServerApproveEntitiesToFields(serverApproveEntities, getInstance());
return thisCastToDerived(); return thisCastToDerived();
} }
@Override @Override
public T build() { public T build() {
mapServerApproveEntitiesToFields(getInstance().serverApproveEntities, getInstance()); if (getInstance().pollMessageId1 != null) {
checkState(getInstance().repoId != null, "Repo id undefined");
checkState(getInstance().historyEntryId != null, "History entry undefined");
}
return super.build(); return super.build();
} }
} }

View file

@ -103,7 +103,7 @@ public class EppHistoryVKeyTranslatorFactory
@Nullable @Nullable
@Override @Override
public Key saveValue(@Nullable EppHistoryVKey pojoValue) { public Key saveValue(@Nullable EppHistoryVKey pojoValue) {
return pojoValue == null ? null : pojoValue.createOfyKey().getRaw(); throw new UnsupportedOperationException("saveValue for EppHistory keys removed.");
} }
}; };
} }

View file

@ -69,11 +69,6 @@ public abstract class BillingVKey<K> extends EppHistoryVKey<K, DomainBase> {
super(repoId, historyRevisionId, billingEventId); super(repoId, historyRevisionId, billingEventId);
} }
@Override
public Key<OneTime> createOfyKey() {
return Key.create(createHistoryEntryKey(), BillingEvent.OneTime.class, billingId);
}
/** Creates a {@link BillingEventVKey} instance from the given {@link Key} instance. */ /** Creates a {@link BillingEventVKey} instance from the given {@link Key} instance. */
public static BillingEventVKey create(@Nullable Key<BillingEvent.OneTime> ofyKey) { public static BillingEventVKey create(@Nullable Key<BillingEvent.OneTime> ofyKey) {
if (ofyKey == null) { if (ofyKey == null) {
@ -87,7 +82,7 @@ public abstract class BillingVKey<K> extends EppHistoryVKey<K, DomainBase> {
/** Creates a {@link BillingEventVKey} instance from the given {@link VKey} instance. */ /** Creates a {@link BillingEventVKey} instance from the given {@link VKey} instance. */
public static BillingEventVKey create(@Nullable VKey<BillingEvent.OneTime> vKey) { public static BillingEventVKey create(@Nullable VKey<BillingEvent.OneTime> vKey) {
return vKey == null ? null : create(vKey.getOfyKey()); return vKey == null ? null : new BillingEventVKey(null, 0, (Long) vKey.getSqlKey());
} }
} }
@ -111,11 +106,6 @@ public abstract class BillingVKey<K> extends EppHistoryVKey<K, DomainBase> {
super(repoId, historyRevisionId, billingEventId); super(repoId, historyRevisionId, billingEventId);
} }
@Override
public Key<Recurring> createOfyKey() {
return Key.create(createHistoryEntryKey(), BillingEvent.Recurring.class, billingId);
}
/** Creates a {@link BillingRecurrenceVKey} instance from the given {@link Key} instance. */ /** Creates a {@link BillingRecurrenceVKey} instance from the given {@link Key} instance. */
public static BillingRecurrenceVKey create(@Nullable Key<BillingEvent.Recurring> ofyKey) { public static BillingRecurrenceVKey create(@Nullable Key<BillingEvent.Recurring> ofyKey) {
if (ofyKey == null) { if (ofyKey == null) {
@ -129,7 +119,7 @@ public abstract class BillingVKey<K> extends EppHistoryVKey<K, DomainBase> {
/** Creates a {@link BillingRecurrenceVKey} instance from the given {@link VKey} instance. */ /** Creates a {@link BillingRecurrenceVKey} instance from the given {@link VKey} instance. */
public static BillingRecurrenceVKey create(@Nullable VKey<BillingEvent.Recurring> vKey) { public static BillingRecurrenceVKey create(@Nullable VKey<BillingEvent.Recurring> vKey) {
return vKey == null ? null : create(vKey.getOfyKey()); return vKey == null ? null : new BillingRecurrenceVKey(null, 0, (Long) vKey.getSqlKey());
} }
} }
} }

View file

@ -40,11 +40,6 @@ public class DomainHistoryVKey extends EppHistoryVKey<HistoryEntry, DomainBase>
return new DomainHistoryId(repoId, historyRevisionId); return new DomainHistoryId(repoId, historyRevisionId);
} }
@Override
public Key<HistoryEntry> createOfyKey() {
return Key.create(Key.create(DomainBase.class, repoId), HistoryEntry.class, historyRevisionId);
}
/** Creates {@link DomainHistoryVKey} from the given {@link Key} instance. */ /** Creates {@link DomainHistoryVKey} from the given {@link Key} instance. */
public static DomainHistoryVKey create(Key<? extends HistoryEntry> ofyKey) { public static DomainHistoryVKey create(Key<? extends HistoryEntry> ofyKey) {
checkArgumentNotNull(ofyKey, "ofyKey must be specified"); checkArgumentNotNull(ofyKey, "ofyKey must be specified");

View file

@ -99,10 +99,8 @@ public abstract class EppHistoryVKey<K, E extends EppResource> extends Immutable
@Override @Override
public VKey<K> createVKey() { public VKey<K> createVKey() {
Class<K> vKeyType = new TypeInstantiator<K>(getClass()) {}.getExactType(); Class<K> vKeyType = new TypeInstantiator<K>(getClass()) {}.getExactType();
return VKey.create(vKeyType, createSqlKey(), createOfyKey()); return VKey.createSql(vKeyType, createSqlKey());
} }
public abstract Serializable createSqlKey(); public abstract Serializable createSqlKey();
public abstract Key<K> createOfyKey();
} }

View file

@ -16,6 +16,7 @@ package google.registry.persistence;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import static google.registry.model.ImmutableObject.Insignificant;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull; import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
@ -52,7 +53,8 @@ public class VKey<T> extends ImmutableObject implements Serializable {
// The SQL key for the referenced entity. // The SQL key for the referenced entity.
Serializable sqlKey; Serializable sqlKey;
// The objectify key for the referenced entity. // The objectify key for the referenced entity. Marked Insignificant to exclude it from
// hashing/equality.
@Insignificant Key<T> ofyKey; @Insignificant Key<T> ofyKey;
Class<? extends T> kind; Class<? extends T> kind;

View file

@ -118,7 +118,7 @@ class EnqueuePollMessageCommand extends MutatingCommand {
null, null,
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setRegistrarId(registrarId) .setRegistrarId(registrarId)
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.setEventTime(tm().getTransactionTime()) .setEventTime(tm().getTransactionTime())
.setMsg(message) .setMsg(message)
.build()); .build());

View file

@ -201,7 +201,7 @@ class UnrenewDomainCommand extends ConfirmingCommand implements CommandWithRemot
String.format( String.format(
"Domain %s was unrenewed by %d years; now expires at %s.", "Domain %s was unrenewed by %d years; now expires at %s.",
domainName, period, newExpirationTime)) domainName, period, newExpirationTime))
.setParent(domainHistory) .setHistoryEntry(domainHistory)
.setEventTime(now) .setEventTime(now)
.build(); .build();
// Create a new autorenew billing event and poll message starting at the new expiration time. // Create a new autorenew billing event and poll message starting at the new expiration time.
@ -213,7 +213,7 @@ class UnrenewDomainCommand extends ConfirmingCommand implements CommandWithRemot
PollMessage.Autorenew newAutorenewPollMessage = PollMessage.Autorenew newAutorenewPollMessage =
newAutorenewPollMessage(domain) newAutorenewPollMessage(domain)
.setEventTime(newExpirationTime) .setEventTime(newExpirationTime)
.setParent(domainHistory) .setHistoryEntry(domainHistory)
.build(); .build();
// End the old autorenew billing event and poll message now. // End the old autorenew billing event and poll message now.
updateAutorenewRecurrenceEndTime(domain, now); updateAutorenewRecurrenceEndTime(domain, now);
@ -224,7 +224,9 @@ class UnrenewDomainCommand extends ConfirmingCommand implements CommandWithRemot
.setLastEppUpdateTime(now) .setLastEppUpdateTime(now)
.setLastEppUpdateRegistrarId(domain.getCurrentSponsorRegistrarId()) .setLastEppUpdateRegistrarId(domain.getCurrentSponsorRegistrarId())
.setAutorenewBillingEvent(newAutorenewEvent.createVKey()) .setAutorenewBillingEvent(newAutorenewEvent.createVKey())
.setAutorenewPollMessage(newAutorenewPollMessage.createVKey()) .setAutorenewPollMessage(
newAutorenewPollMessage.createVKey(),
newAutorenewPollMessage.getHistoryRevisionId())
.build(); .build();
// In order to do it'll need to write out a new HistoryEntry (likely of type SYNTHETIC), a new // In order to do it'll need to write out a new HistoryEntry (likely of type SYNTHETIC), a new
// autorenew billing event and poll message, and a new one time poll message at the present time // autorenew billing event and poll message, and a new one time poll message at the present time

View file

@ -191,7 +191,8 @@ class DeleteExpiredDomainsActionTest {
.asBuilder() .asBuilder()
.setAutorenewEndTime(Optional.of(clock.nowUtc().minusDays(10))) .setAutorenewEndTime(Optional.of(clock.nowUtc().minusDays(10)))
.setAutorenewBillingEvent(autorenewBillingEvent.createVKey()) .setAutorenewBillingEvent(autorenewBillingEvent.createVKey())
.setAutorenewPollMessage(autorenewPollMessage.createVKey()) .setAutorenewPollMessage(
autorenewPollMessage.createVKey(), autorenewPollMessage.getHistoryRevisionId())
.build()); .build());
return pendingExpirationDomain; return pendingExpirationDomain;
@ -216,6 +217,6 @@ class DeleteExpiredDomainsActionTest {
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(clock.nowUtc().plusYears(1)) .setEventTime(clock.nowUtc().plusYears(1))
.setAutorenewEndTime(END_OF_TIME) .setAutorenewEndTime(END_OF_TIME)
.setParent(createHistoryEntry); .setHistoryEntry(createHistoryEntry);
} }
} }

View file

@ -316,7 +316,7 @@ class DeleteProberDataActionTest {
PollMessage.OneTime pollMessage = PollMessage.OneTime pollMessage =
persistSimpleResource( persistSimpleResource(
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.setEventTime(DELETION_TIME) .setEventTime(DELETION_TIME)
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setMsg("Domain registered") .setMsg("Domain registered")

View file

@ -311,6 +311,10 @@ public class RdePipelineTest {
persistDomainHistory( persistDomainHistory(
helloDomain helloDomain
.asBuilder() .asBuilder()
.removeContacts(
helloDomain.getContacts().stream()
.filter(dc -> dc.getType() == DesignatedContact.Type.ADMIN)
.collect(toImmutableSet()))
.addContacts( .addContacts(
ImmutableSet.of( ImmutableSet.of(
DesignatedContact.create(DesignatedContact.Type.ADMIN, contact3.createVKey()))) DesignatedContact.create(DesignatedContact.Type.ADMIN, contact3.createVKey())))

View file

@ -107,6 +107,8 @@ class ContactTransferRequestFlowTest
// Make the server-approve entities field a no-op comparison; it's easier to // Make the server-approve entities field a no-op comparison; it's easier to
// do this comparison separately below. // do this comparison separately below.
.setServerApproveEntities( .setServerApproveEntities(
contact.getRepoId(),
contact.getTransferData().getHistoryEntryId(),
forceEmptyToNull(contact.getTransferData().getServerApproveEntities())) forceEmptyToNull(contact.getTransferData().getServerApproveEntities()))
.build()); .build());
assertNoBillingEvents(); assertNoBillingEvents();

View file

@ -34,7 +34,7 @@ public class TestDomainCreateFlowCustomLogic extends DomainCreateFlowCustomLogic
if (parameters.newDomain().getDomainName().startsWith("custom-logic-test")) { if (parameters.newDomain().getDomainName().startsWith("custom-logic-test")) {
PollMessage extraPollMessage = PollMessage extraPollMessage =
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setParent(parameters.historyEntry()) .setHistoryEntry(parameters.historyEntry())
.setEventTime(tm().getTransactionTime()) .setEventTime(tm().getTransactionTime())
.setRegistrarId(getSessionMetadata().get().getRegistrarId()) .setRegistrarId(getSessionMetadata().get().getRegistrarId())
.setMsg("Custom logic was triggered") .setMsg("Custom logic was triggered")

View file

@ -348,7 +348,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(domain.getRegistrationExpirationTime()) .setEventTime(domain.getRegistrationExpirationTime())
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.build()); .build());
assertGracePeriods( assertGracePeriods(
@ -1656,10 +1656,10 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(domain.getRegistrationExpirationTime()) .setEventTime(domain.getRegistrationExpirationTime())
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.build(), .build(),
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.setEventTime(domain.getCreationTime()) .setEventTime(domain.getCreationTime())
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setMsg(DomainFlowUtils.COLLISION_MESSAGE) .setMsg(DomainFlowUtils.COLLISION_MESSAGE)
@ -1811,10 +1811,10 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(domain.getRegistrationExpirationTime()) .setEventTime(domain.getRegistrationExpirationTime())
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.build(), .build(),
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.setEventTime(domain.getCreationTime()) .setEventTime(domain.getCreationTime())
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setMsg("Custom logic was triggered") .setMsg("Custom logic was triggered")

View file

@ -149,7 +149,8 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
domain domain
.asBuilder() .asBuilder()
.setAutorenewBillingEvent(autorenewBillingEvent.createVKey()) .setAutorenewBillingEvent(autorenewBillingEvent.createVKey())
.setAutorenewPollMessage(autorenewPollMessage.createVKey()) .setAutorenewPollMessage(
autorenewPollMessage.createVKey(), autorenewPollMessage.getHistoryRevisionId())
.build()); .build());
assertTransactionalFlow(true); assertTransactionalFlow(true);
@ -215,7 +216,8 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
"TheRegistrar", "TheRegistrar",
autorenewBillingEvent.createVKey()))) autorenewBillingEvent.createVKey())))
.setAutorenewBillingEvent(autorenewBillingEvent.createVKey()) .setAutorenewBillingEvent(autorenewBillingEvent.createVKey())
.setAutorenewPollMessage(autorenewPollMessage.createVKey()) .setAutorenewPollMessage(
autorenewPollMessage.createVKey(), autorenewPollMessage.getHistoryRevisionId())
.build()); .build());
assertTransactionalFlow(true); assertTransactionalFlow(true);
} }
@ -281,7 +283,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
.setRegistrarId(registrarId) .setRegistrarId(registrarId)
.setEventTime(A_MONTH_FROM_NOW) .setEventTime(A_MONTH_FROM_NOW)
.setAutorenewEndTime(END_OF_TIME) .setAutorenewEndTime(END_OF_TIME)
.setParent(earlierHistoryEntry); .setHistoryEntry(earlierHistoryEntry);
} }
@TestOfyAndSql @TestOfyAndSql
@ -481,8 +483,8 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
DateTime deletionTime = domain.getDeletionTime(); DateTime deletionTime = domain.getDeletionTime();
assertThat(getPollMessages("TheRegistrar", deletionTime.minusMinutes(1))).isEmpty(); assertThat(getPollMessages("TheRegistrar", deletionTime.minusMinutes(1))).isEmpty();
assertThat(getPollMessages("TheRegistrar", deletionTime)).hasSize(1); assertThat(getPollMessages("TheRegistrar", deletionTime)).hasSize(1);
assertThat(domain.getDeletePollMessage().getOfyKey()) assertThat(domain.getDeletePollMessage())
.isEqualTo(getOnlyPollMessage("TheRegistrar").createVKey().getOfyKey()); .isEqualTo(getOnlyPollMessage("TheRegistrar").createVKey());
PollMessage.OneTime deletePollMessage = loadByKey(domain.getDeletePollMessage()); PollMessage.OneTime deletePollMessage = loadByKey(domain.getDeletePollMessage());
assertThat(deletePollMessage.getMsg()).isEqualTo(expectedMessage); assertThat(deletePollMessage.getMsg()).isEqualTo(expectedMessage);
} }
@ -841,7 +843,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
assertPollMessages( assertPollMessages(
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setParent(deleteHistoryEntry) .setHistoryEntry(deleteHistoryEntry)
.setEventTime(now) .setEventTime(now)
.setMsg( .setMsg(
"Domain example.tld was deleted by registry administrator with final deletion" "Domain example.tld was deleted by registry administrator with final deletion"
@ -853,7 +855,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
.build(), .build(),
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setParent(deleteHistoryEntry) .setHistoryEntry(deleteHistoryEntry)
.setEventTime(DateTime.parse("2000-07-11T22:00:00.012Z")) .setEventTime(DateTime.parse("2000-07-11T22:00:00.012Z"))
.setMsg("Deleted by registry administrator.") .setMsg("Deleted by registry administrator.")
.setResponseData( .setResponseData(

View file

@ -169,7 +169,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, DomainBa
.setEventTime(expirationTime) .setEventTime(expirationTime)
.setAutorenewEndTime(END_OF_TIME) .setAutorenewEndTime(END_OF_TIME)
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setParent(historyEntryDomainCreate) .setHistoryEntry(historyEntryDomainCreate)
.build(); .build();
DomainBase newDomain = DomainBase newDomain =
domain domain
@ -177,7 +177,9 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, DomainBa
.setRegistrationExpirationTime(expirationTime) .setRegistrationExpirationTime(expirationTime)
.setStatusValues(ImmutableSet.copyOf(statusValues)) .setStatusValues(ImmutableSet.copyOf(statusValues))
.setAutorenewBillingEvent(autorenewEvent.createVKey()) .setAutorenewBillingEvent(autorenewEvent.createVKey())
.setAutorenewPollMessage(autorenewPollMessage.createVKey()) .setAutorenewPollMessage(
autorenewPollMessage.createVKey(),
autorenewPollMessage.getHistoryRevisionId())
.build(); .build();
persistResources( persistResources(
ImmutableSet.of( ImmutableSet.of(
@ -307,7 +309,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, DomainBa
.setEventTime(domain.getRegistrationExpirationTime()) .setEventTime(domain.getRegistrationExpirationTime())
.setAutorenewEndTime(END_OF_TIME) .setAutorenewEndTime(END_OF_TIME)
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setParent(historyEntryDomainRenew) .setHistoryEntry(historyEntryDomainRenew)
.build()); .build());
assertGracePeriods( assertGracePeriods(
domain.getGracePeriods(), domain.getGracePeriods(),
@ -647,7 +649,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, DomainBa
.setEventTime(expirationTime.minusYears(1)) .setEventTime(expirationTime.minusYears(1))
.setAutorenewEndTime(clock.nowUtc()) .setAutorenewEndTime(clock.nowUtc())
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setParent( .setHistoryEntry(
getOnlyHistoryEntryOfType( getOnlyHistoryEntryOfType(
reloadResourceByForeignKey(), HistoryEntry.Type.DOMAIN_CREATE)) reloadResourceByForeignKey(), HistoryEntry.Type.DOMAIN_CREATE))
.build(), .build(),
@ -657,7 +659,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, DomainBa
.setEventTime(reloadResourceByForeignKey().getRegistrationExpirationTime()) .setEventTime(reloadResourceByForeignKey().getRegistrationExpirationTime())
.setAutorenewEndTime(END_OF_TIME) .setAutorenewEndTime(END_OF_TIME)
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setParent(historyEntryDomainRenew) .setHistoryEntry(historyEntryDomainRenew)
.build()); .build());
} }

View file

@ -139,7 +139,7 @@ class DomainRestoreRequestFlowTest
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(clock.nowUtc().plusDays(5)) .setEventTime(clock.nowUtc().plusDays(5))
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.build()) .build())
.createVKey()) .createVKey())
.build()); .build());
@ -202,7 +202,7 @@ class DomainRestoreRequestFlowTest
.setEventTime(domain.getRegistrationExpirationTime()) .setEventTime(domain.getRegistrationExpirationTime())
.setAutorenewEndTime(END_OF_TIME) .setAutorenewEndTime(END_OF_TIME)
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setParent(historyEntryDomainRestore) .setHistoryEntry(historyEntryDomainRestore)
.build()); .build());
// There should be a onetime for the restore and a new recurring billing event, but no renew // There should be a onetime for the restore and a new recurring billing event, but no renew
// onetime. // onetime.
@ -271,7 +271,7 @@ class DomainRestoreRequestFlowTest
.setEventTime(domain.getRegistrationExpirationTime()) .setEventTime(domain.getRegistrationExpirationTime())
.setAutorenewEndTime(END_OF_TIME) .setAutorenewEndTime(END_OF_TIME)
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setParent(historyEntryDomainRestore) .setHistoryEntry(historyEntryDomainRestore)
.build()); .build());
// There should be a bill for the restore and an explicit renew, along with a new recurring // There should be a bill for the restore and an explicit renew, along with a new recurring
// autorenew event. // autorenew event.

View file

@ -97,7 +97,7 @@ class DomainTransferCancelFlowTest
.setEventTime(EXTENDED_REGISTRATION_EXPIRATION_TIME) .setEventTime(EXTENDED_REGISTRATION_EXPIRATION_TIME)
.setAutorenewEndTime(END_OF_TIME) .setAutorenewEndTime(END_OF_TIME)
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setParent(historyEntryDomainTransferRequest) .setHistoryEntry(historyEntryDomainTransferRequest)
.build(), .build(),
createPollMessageForImplicitTransfer( createPollMessageForImplicitTransfer(
domain, domain,
@ -164,7 +164,7 @@ class DomainTransferCancelFlowTest
.setEventTime(originalExpirationTime) .setEventTime(originalExpirationTime)
.setAutorenewEndTime(END_OF_TIME) .setAutorenewEndTime(END_OF_TIME)
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setParent(getOnlyHistoryEntryOfType(domain, DOMAIN_CREATE)) .setHistoryEntry(getOnlyHistoryEntryOfType(domain, DOMAIN_CREATE))
.build(), .build(),
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
@ -180,7 +180,7 @@ class DomainTransferCancelFlowTest
.setPendingTransferExpirationTime(clock.nowUtc()) .setPendingTransferExpirationTime(clock.nowUtc())
.build())) .build()))
.setMsg("Transfer cancelled.") .setMsg("Transfer cancelled.")
.setParent(getOnlyHistoryEntryOfType(domain, DOMAIN_TRANSFER_CANCEL)) .setHistoryEntry(getOnlyHistoryEntryOfType(domain, DOMAIN_TRANSFER_CANCEL))
.build()); .build());
// The original grace periods should remain untouched. // The original grace periods should remain untouched.

View file

@ -1160,7 +1160,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
updatedDomain, updatedDomain,
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setEventTime(clock.nowUtc()) .setEventTime(clock.nowUtc())
.setParent(getOnlyHistoryEntryOfType(updatedDomain, DOMAIN_UPDATE)) .setHistoryEntry(getOnlyHistoryEntryOfType(updatedDomain, DOMAIN_UPDATE))
.setRegistrarId("NewRegistrar") .setRegistrarId("NewRegistrar")
.setMsg("The registry administrator has added the status(es) [serverHold].") .setMsg("The registry administrator has added the status(es) [serverHold].")
.setResponseData( .setResponseData(
@ -1199,7 +1199,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
updatedDomain, updatedDomain,
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setEventTime(clock.nowUtc()) .setEventTime(clock.nowUtc())
.setParent(getOnlyHistoryEntryOfType(updatedDomain, DOMAIN_UPDATE)) .setHistoryEntry(getOnlyHistoryEntryOfType(updatedDomain, DOMAIN_UPDATE))
.setRegistrarId("NewRegistrar") .setRegistrarId("NewRegistrar")
.setMsg( .setMsg(
"The registry administrator has removed the status(es) [serverHold," "The registry administrator has removed the status(es) [serverHold,"
@ -1237,7 +1237,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
updatedDomain, updatedDomain,
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setEventTime(clock.nowUtc()) .setEventTime(clock.nowUtc())
.setParent(getOnlyHistoryEntryOfType(updatedDomain, DOMAIN_UPDATE)) .setHistoryEntry(getOnlyHistoryEntryOfType(updatedDomain, DOMAIN_UPDATE))
.setRegistrarId("NewRegistrar") .setRegistrarId("NewRegistrar")
.setMsg( .setMsg(
"The registry administrator has added the status(es) [serverHold," "The registry administrator has added the status(es) [serverHold,"

View file

@ -70,7 +70,7 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
.setRegistrarId(getRegistrarIdForFlow()) .setRegistrarId(getRegistrarIdForFlow())
.setEventTime(clock.nowUtc().minusDays(1)) .setEventTime(clock.nowUtc().minusDays(1))
.setMsg("Some poll message.") .setMsg("Some poll message.")
.setParent(createHistoryEntryForEppResource(domain)) .setHistoryEntry(createHistoryEntryForEppResource(domain))
.build()); .build());
} }
@ -83,7 +83,7 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
.setAutorenewEndTime(endTime) .setAutorenewEndTime(endTime)
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setTargetId("example.com") .setTargetId("example.com")
.setParent(createHistoryEntryForEppResource(domain)) .setHistoryEntry(createHistoryEntryForEppResource(domain))
.build()); .build());
} }
@ -102,7 +102,7 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
.setRegistrarId(getRegistrarIdForFlow()) .setRegistrarId(getRegistrarIdForFlow())
.setEventTime(clock.nowUtc().minusDays(1)) .setEventTime(clock.nowUtc().minusDays(1))
.setMsg("Some poll message.") .setMsg("Some poll message.")
.setParent(createHistoryEntryForEppResource(contact)) .setHistoryEntry(createHistoryEntryForEppResource(contact))
.build()); .build());
assertTransactionalFlow(true); assertTransactionalFlow(true);
runFlowAssertResponse(loadFile("poll_ack_response_empty.xml")); runFlowAssertResponse(loadFile("poll_ack_response_empty.xml"));
@ -117,7 +117,7 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
.setRegistrarId(getRegistrarIdForFlow()) .setRegistrarId(getRegistrarIdForFlow())
.setEventTime(clock.nowUtc().minusDays(1)) .setEventTime(clock.nowUtc().minusDays(1))
.setMsg("Some poll message.") .setMsg("Some poll message.")
.setParent(createHistoryEntryForEppResource(contact)) .setHistoryEntry(createHistoryEntryForEppResource(contact))
.build()); .build());
assertTransactionalFlow(true); assertTransactionalFlow(true);
assertThrows(MessageDoesNotExistException.class, this::runFlow); assertThrows(MessageDoesNotExistException.class, this::runFlow);
@ -205,7 +205,7 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
.setRegistrarId(getRegistrarIdForFlow()) .setRegistrarId(getRegistrarIdForFlow())
.setEventTime(clock.nowUtc().minusDays(1)) .setEventTime(clock.nowUtc().minusDays(1))
.setMsg("Some poll message.") .setMsg("Some poll message.")
.setParent(createHistoryEntryForEppResource(contact)) .setHistoryEntry(createHistoryEntryForEppResource(contact))
.build()); .build());
assertTransactionalFlow(true); assertTransactionalFlow(true);
assertThrows(InvalidMessageIdException.class, this::runFlow); assertThrows(InvalidMessageIdException.class, this::runFlow);
@ -240,7 +240,7 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(clock.nowUtc().minusDays(1)) .setEventTime(clock.nowUtc().minusDays(1))
.setMsg("Some poll message.") .setMsg("Some poll message.")
.setParent(createHistoryEntryForEppResource(domain)) .setHistoryEntry(createHistoryEntryForEppResource(domain))
.build()); .build());
assertTransactionalFlow(true); assertTransactionalFlow(true);
assertThrows(NotAuthorizedToAckMessageException.class, this::runFlow); assertThrows(NotAuthorizedToAckMessageException.class, this::runFlow);
@ -254,7 +254,7 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
.setRegistrarId(getRegistrarIdForFlow()) .setRegistrarId(getRegistrarIdForFlow())
.setEventTime(clock.nowUtc().plusDays(1)) .setEventTime(clock.nowUtc().plusDays(1))
.setMsg("Some poll message.") .setMsg("Some poll message.")
.setParent(createHistoryEntryForEppResource(domain)) .setHistoryEntry(createHistoryEntryForEppResource(domain))
.build()); .build());
assertTransactionalFlow(true); assertTransactionalFlow(true);
Exception e = assertThrows(MessageDoesNotExistException.class, this::runFlow); Exception e = assertThrows(MessageDoesNotExistException.class, this::runFlow);

View file

@ -87,7 +87,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
.setPendingTransferExpirationTime(clock.nowUtc().minusDays(1)) .setPendingTransferExpirationTime(clock.nowUtc().minusDays(1))
.setExtendedRegistrationExpirationTime(clock.nowUtc().plusYears(1)) .setExtendedRegistrationExpirationTime(clock.nowUtc().plusYears(1))
.build())) .build()))
.setParent(createHistoryEntryForEppResource(domain)) .setHistoryEntry(createHistoryEntryForEppResource(domain))
.build()); .build());
} }
@ -125,7 +125,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
.setLosingRegistrarId("NewRegistrar") .setLosingRegistrarId("NewRegistrar")
.setPendingTransferExpirationTime(clock.nowUtc()) .setPendingTransferExpirationTime(clock.nowUtc())
.build())) .build()))
.setParent(createHistoryEntryForEppResource(contact)) .setHistoryEntry(createHistoryEntryForEppResource(contact))
.build()); .build());
assertTransactionalFlow(false); assertTransactionalFlow(false);
runFlowAssertResponse(loadFile("poll_response_contact_transfer.xml")); runFlowAssertResponse(loadFile("poll_response_contact_transfer.xml"));
@ -145,7 +145,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
true, true,
Trid.create("ABC-12345", "other-trid"), Trid.create("ABC-12345", "other-trid"),
clock.nowUtc()))) clock.nowUtc())))
.setParent(createHistoryEntryForEppResource(domain)) .setHistoryEntry(createHistoryEntryForEppResource(domain))
.build()); .build());
assertTransactionalFlow(false); assertTransactionalFlow(false);
runFlowAssertResponse(loadFile("poll_response_domain_pending_notification.xml")); runFlowAssertResponse(loadFile("poll_response_domain_pending_notification.xml"));
@ -169,7 +169,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
true, true,
Trid.create("ABC-12345", "other-trid"), Trid.create("ABC-12345", "other-trid"),
clock.nowUtc()))) clock.nowUtc())))
.setParent(createHistoryEntryForEppResource(domain)) .setHistoryEntry(createHistoryEntryForEppResource(domain))
.build()); .build());
assertTransactionalFlow(false); assertTransactionalFlow(false);
runFlowAssertResponse(loadFile("poll_message_domain_pending_action_immediate_delete.xml")); runFlowAssertResponse(loadFile("poll_message_domain_pending_action_immediate_delete.xml"));
@ -183,7 +183,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
.setEventTime(clock.nowUtc().minusDays(1)) .setEventTime(clock.nowUtc().minusDays(1))
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setTargetId("test.example") .setTargetId("test.example")
.setParent(createHistoryEntryForEppResource(domain)) .setHistoryEntry(createHistoryEntryForEppResource(domain))
.build()); .build());
assertTransactionalFlow(false); assertTransactionalFlow(false);
runFlowAssertResponse(loadFile("poll_response_autorenew.xml")); runFlowAssertResponse(loadFile("poll_response_autorenew.xml"));
@ -201,7 +201,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
.setRegistrarId("BadRegistrar") .setRegistrarId("BadRegistrar")
.setEventTime(clock.nowUtc().minusDays(1)) .setEventTime(clock.nowUtc().minusDays(1))
.setMsg("Poll message") .setMsg("Poll message")
.setParent(createHistoryEntryForEppResource(domain)) .setHistoryEntry(createHistoryEntryForEppResource(domain))
.build()); .build());
runFlowAssertResponse(loadFile("poll_response_empty.xml")); runFlowAssertResponse(loadFile("poll_response_empty.xml"));
} }
@ -213,7 +213,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
.setRegistrarId(getRegistrarIdForFlow()) .setRegistrarId(getRegistrarIdForFlow())
.setEventTime(clock.nowUtc().plusDays(1)) .setEventTime(clock.nowUtc().plusDays(1))
.setMsg("Poll message") .setMsg("Poll message")
.setParent(createHistoryEntryForEppResource(domain)) .setHistoryEntry(createHistoryEntryForEppResource(domain))
.build()); .build());
runFlowAssertResponse(loadFile("poll_response_empty.xml")); runFlowAssertResponse(loadFile("poll_response_empty.xml"));
} }
@ -226,7 +226,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
.setEventTime(clock.nowUtc().plusDays(1)) .setEventTime(clock.nowUtc().plusDays(1))
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setTargetId("target.example") .setTargetId("target.example")
.setParent(createHistoryEntryForEppResource(domain)) .setHistoryEntry(createHistoryEntryForEppResource(domain))
.build()); .build());
assertTransactionalFlow(false); assertTransactionalFlow(false);
runFlowAssertResponse(loadFile("poll_response_empty.xml")); runFlowAssertResponse(loadFile("poll_response_empty.xml"));
@ -248,7 +248,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setRegistrarId("NewRegistrar") .setRegistrarId("NewRegistrar")
.setMsg("Deleted contact jd1234") .setMsg("Deleted contact jd1234")
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.setEventTime(clock.nowUtc().minusDays(1)) .setEventTime(clock.nowUtc().minusDays(1))
.build()); .build());
assertTransactionalFlow(false); assertTransactionalFlow(false);
@ -271,7 +271,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setRegistrarId("NewRegistrar") .setRegistrarId("NewRegistrar")
.setMsg("Deleted host ns1.test.example") .setMsg("Deleted host ns1.test.example")
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.setEventTime(clock.nowUtc().minusDays(1)) .setEventTime(clock.nowUtc().minusDays(1))
.build()); .build());
clock.advanceOneMilli(); clock.advanceOneMilli();

View file

@ -156,7 +156,7 @@ public class ContactResourceTest extends EntityTestCase {
originalContact originalContact
.getTransferData() .getTransferData()
.asBuilder() .asBuilder()
.setServerApproveEntities(null) .setServerApproveEntities(null, null, null)
.build()) .build())
.build(); .build();
assertAboutImmutableObjects().that(persisted).isEqualExceptFields(fixed, "updateTimestamp"); assertAboutImmutableObjects().that(persisted).isEqualExceptFields(fixed, "updateTimestamp");

View file

@ -422,14 +422,14 @@ public class DomainBaseSqlTest {
.setId(300L) .setId(300L)
.setRegistrarId("registrar1") .setRegistrarId("registrar1")
.setEventTime(DateTime.now(UTC).plusYears(1)) .setEventTime(DateTime.now(UTC).plusYears(1))
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.build(); .build();
PollMessage.OneTime deletePollMessage = PollMessage.OneTime deletePollMessage =
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setId(400L) .setId(400L)
.setRegistrarId("registrar1") .setRegistrarId("registrar1")
.setEventTime(DateTime.now(UTC).plusYears(1)) .setEventTime(DateTime.now(UTC).plusYears(1))
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.build(); .build();
BillingEvent.OneTime oneTimeBillingEvent = BillingEvent.OneTime oneTimeBillingEvent =
new BillingEvent.OneTime.Builder() new BillingEvent.OneTime.Builder()
@ -469,7 +469,8 @@ public class DomainBaseSqlTest {
domain domain
.asBuilder() .asBuilder()
.setAutorenewBillingEvent(billEvent.createVKey()) .setAutorenewBillingEvent(billEvent.createVKey())
.setAutorenewPollMessage(autorenewPollMessage.createVKey()) .setAutorenewPollMessage(
autorenewPollMessage.createVKey(), autorenewPollMessage.getHistoryRevisionId())
.setDeletePollMessage(deletePollMessage.createVKey()) .setDeletePollMessage(deletePollMessage.createVKey())
.setTransferData(transferData) .setTransferData(transferData)
.setGracePeriods(gracePeriods) .setGracePeriods(gracePeriods)
@ -548,14 +549,14 @@ public class DomainBaseSqlTest {
.setId(300L) .setId(300L)
.setRegistrarId("registrar1") .setRegistrarId("registrar1")
.setEventTime(DateTime.now(UTC).plusYears(1)) .setEventTime(DateTime.now(UTC).plusYears(1))
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.build(); .build();
PollMessage.OneTime deletePollMessage = PollMessage.OneTime deletePollMessage =
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setId(400L) .setId(400L)
.setRegistrarId("registrar1") .setRegistrarId("registrar1")
.setEventTime(DateTime.now(UTC).plusYears(1)) .setEventTime(DateTime.now(UTC).plusYears(1))
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.build(); .build();
BillingEvent.OneTime oneTimeBillingEvent = BillingEvent.OneTime oneTimeBillingEvent =
new BillingEvent.OneTime.Builder() new BillingEvent.OneTime.Builder()
@ -572,6 +573,8 @@ public class DomainBaseSqlTest {
.build(); .build();
DomainTransferData transferData = DomainTransferData transferData =
createPendingTransferData( createPendingTransferData(
domain.getRepoId(),
historyEntry.getId(),
new DomainTransferData.Builder() new DomainTransferData.Builder()
.setTransferRequestTrid(Trid.create("foo", "bar")) .setTransferRequestTrid(Trid.create("foo", "bar"))
.setTransferRequestTime(fakeClock.nowUtc()) .setTransferRequestTime(fakeClock.nowUtc())
@ -601,7 +604,8 @@ public class DomainBaseSqlTest {
.setAutorenewBillingEvent( .setAutorenewBillingEvent(
createLegacyVKey(BillingEvent.Recurring.class, billEvent.getId())) createLegacyVKey(BillingEvent.Recurring.class, billEvent.getId()))
.setAutorenewPollMessage( .setAutorenewPollMessage(
createLegacyVKey(PollMessage.Autorenew.class, autorenewPollMessage.getId())) createLegacyVKey(PollMessage.Autorenew.class, autorenewPollMessage.getId()),
autorenewPollMessage.getHistoryRevisionId())
.setDeletePollMessage( .setDeletePollMessage(
createLegacyVKey(PollMessage.OneTime.class, deletePollMessage.getId())) createLegacyVKey(PollMessage.OneTime.class, deletePollMessage.getId()))
.setTransferData(transferData) .setTransferData(transferData)

View file

@ -21,6 +21,7 @@ import static com.google.common.truth.Truth8.assertThat;
import static google.registry.model.EppResourceUtils.loadByForeignKey; import static google.registry.model.EppResourceUtils.loadByForeignKey;
import static google.registry.testing.DatabaseHelper.cloneAndSetAutoTimestamps; import static google.registry.testing.DatabaseHelper.cloneAndSetAutoTimestamps;
import static google.registry.testing.DatabaseHelper.createTld; import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.insertInDb;
import static google.registry.testing.DatabaseHelper.newDomainBase; import static google.registry.testing.DatabaseHelper.newDomainBase;
import static google.registry.testing.DatabaseHelper.newHostResource; import static google.registry.testing.DatabaseHelper.newHostResource;
import static google.registry.testing.DatabaseHelper.persistActiveContact; import static google.registry.testing.DatabaseHelper.persistActiveContact;
@ -28,6 +29,7 @@ import static google.registry.testing.DatabaseHelper.persistActiveDomain;
import static google.registry.testing.DatabaseHelper.persistActiveHost; import static google.registry.testing.DatabaseHelper.persistActiveHost;
import static google.registry.testing.DatabaseHelper.persistResource; import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.testing.DomainBaseSubject.assertAboutDomains; import static google.registry.testing.DomainBaseSubject.assertAboutDomains;
import static google.registry.testing.SqlHelper.saveRegistrar;
import static google.registry.util.DateTimeUtils.END_OF_TIME; import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static google.registry.util.DateTimeUtils.START_OF_TIME; import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.joda.money.CurrencyUnit.USD; import static org.joda.money.CurrencyUnit.USD;
@ -41,7 +43,6 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Ordering; import com.google.common.collect.Ordering;
import com.google.common.collect.Streams; import com.google.common.collect.Streams;
import com.googlecode.objectify.Key; import com.googlecode.objectify.Key;
import google.registry.model.EntityTestCase;
import google.registry.model.ImmutableObject; import google.registry.model.ImmutableObject;
import google.registry.model.ImmutableObjectSubject; import google.registry.model.ImmutableObjectSubject;
import google.registry.model.billing.BillingEvent; import google.registry.model.billing.BillingEvent;
@ -62,15 +63,28 @@ import google.registry.model.tld.Registry;
import google.registry.model.transfer.DomainTransferData; import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferStatus; import google.registry.model.transfer.TransferStatus;
import google.registry.persistence.VKey; import google.registry.persistence.VKey;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.FakeClock;
import java.util.Optional; import java.util.Optional;
import org.joda.money.Money; import org.joda.money.Money;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link DomainBase}. */ /** Unit tests for {@link DomainBase}. */
@SuppressWarnings("WeakerAccess") // Referred to by EppInputTest. @SuppressWarnings("WeakerAccess") // Referred to by EppInputTest.
public class DomainBaseTest extends EntityTestCase { public class DomainBaseTest {
protected FakeClock fakeClock = new FakeClock(DateTime.now(UTC));
@RegisterExtension
public final AppEngineExtension appEngine =
AppEngineExtension.builder()
.withDatastoreAndCloudSql()
.enableJpaEntityCoverageCheck(true)
.withClock(fakeClock)
.build();
private DomainBase domain; private DomainBase domain;
private VKey<BillingEvent.OneTime> oneTimeBillKey; private VKey<BillingEvent.OneTime> oneTimeBillKey;
@ -80,6 +94,10 @@ public class DomainBaseTest extends EntityTestCase {
@BeforeEach @BeforeEach
void setUp() { void setUp() {
saveRegistrar("registrar1");
saveRegistrar("registrar2");
saveRegistrar("losing");
saveRegistrar("gaining");
createTld("com"); createTld("com");
domain = persistActiveDomain("example.com"); domain = persistActiveDomain("example.com");
VKey<HostResource> hostKey = persistActiveHost("ns1.example.com").createVKey(); VKey<HostResource> hostKey = persistActiveHost("ns1.example.com").createVKey();
@ -107,19 +125,48 @@ public class DomainBaseTest extends EntityTestCase {
.setParent(domainHistory) .setParent(domainHistory)
.build()) .build())
.createVKey(); .createVKey();
recurringBillKey = DomainHistory historyEntry =
persistResource( new DomainHistory.Builder()
new BillingEvent.Recurring.Builder() .setId(100L)
.setReason(Reason.RENEW) .setType(HistoryEntry.Type.DOMAIN_CREATE)
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) .setPeriod(Period.create(1, Period.Unit.YEARS))
.setTargetId(domain.getDomainName()) .setModificationTime(DateTime.now(UTC))
.setRegistrarId(domain.getCurrentSponsorRegistrarId()) .setDomainRepoId(domain.getRepoId())
.setDomainRepoId(domain.getRepoId()) .setRegistrarId(domain.getCurrentSponsorRegistrarId())
.setEventTime(DateTime.now(UTC).plusYears(1)) // These are non-null, but I don't think some tests set them.
.setRecurrenceEndTime(END_OF_TIME) .setReason("felt like it")
.setParent(domainHistory) .setRequestedByRegistrar(false)
.build()) .setXmlBytes(new byte[0])
.createVKey(); .build();
BillingEvent.OneTime oneTimeBill =
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")
.setRegistrarId("registrar1")
.setDomainRepoId("4-COM")
.setBillingTime(DateTime.now(UTC))
.setCost(Money.of(USD, 100))
.setEventTime(DateTime.now(UTC).plusYears(1))
.setParent(historyEntry)
.build();
oneTimeBillKey = oneTimeBill.createVKey();
BillingEvent.Recurring recurringBill =
new BillingEvent.Recurring.Builder()
.setId(200L)
.setReason(Reason.RENEW)
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
.setTargetId(domain.getDomainName())
.setRegistrarId(domain.getCurrentSponsorRegistrarId())
.setDomainRepoId(domain.getRepoId())
.setDomainHistoryRevisionId(historyEntry.getId())
.setEventTime(DateTime.now(UTC).plusYears(1))
.setRecurrenceEndTime(END_OF_TIME)
.setParent(historyEntry)
.build();
insertInDb(historyEntry, oneTimeBill, recurringBill);
recurringBillKey = recurringBill.createVKey();
VKey<PollMessage.Autorenew> autorenewPollKey = VKey<PollMessage.Autorenew> autorenewPollKey =
VKey.from(Key.create(Key.create(domainHistory), PollMessage.Autorenew.class, 3)); VKey.from(Key.create(Key.create(domainHistory), PollMessage.Autorenew.class, 3));
VKey<PollMessage.OneTime> onetimePollKey = VKey<PollMessage.OneTime> onetimePollKey =
@ -134,6 +181,7 @@ public class DomainBaseTest extends EntityTestCase {
.setCreationRegistrarId("TheRegistrar") .setCreationRegistrarId("TheRegistrar")
.setLastEppUpdateTime(fakeClock.nowUtc()) .setLastEppUpdateTime(fakeClock.nowUtc())
.setLastEppUpdateRegistrarId("NewRegistrar") .setLastEppUpdateRegistrarId("NewRegistrar")
.setPersistedCurrentSponsorRegistrarId("NewRegistrar")
.setLastTransferTime(fakeClock.nowUtc()) .setLastTransferTime(fakeClock.nowUtc())
.setStatusValues( .setStatusValues(
ImmutableSet.of( ImmutableSet.of(
@ -144,7 +192,6 @@ public class DomainBaseTest extends EntityTestCase {
StatusValue.SERVER_RENEW_PROHIBITED, StatusValue.SERVER_RENEW_PROHIBITED,
StatusValue.SERVER_HOLD)) StatusValue.SERVER_HOLD))
.setRegistrant(contact1Key) .setRegistrant(contact1Key)
.setContacts(ImmutableSet.of(DesignatedContact.create(Type.ADMIN, contact2Key)))
.setNameservers(ImmutableSet.of(hostKey)) .setNameservers(ImmutableSet.of(hostKey))
.setSubordinateHosts(ImmutableSet.of("ns1.example.com")) .setSubordinateHosts(ImmutableSet.of("ns1.example.com"))
.setPersistedCurrentSponsorRegistrarId("NewRegistrar") .setPersistedCurrentSponsorRegistrarId("NewRegistrar")
@ -160,6 +207,8 @@ public class DomainBaseTest extends EntityTestCase {
.setLosingRegistrarId("NewRegistrar") .setLosingRegistrarId("NewRegistrar")
.setPendingTransferExpirationTime(fakeClock.nowUtc()) .setPendingTransferExpirationTime(fakeClock.nowUtc())
.setServerApproveEntities( .setServerApproveEntities(
historyEntry.getDomainRepoId(),
historyEntry.getId(),
ImmutableSet.of(oneTimeBillKey, recurringBillKey, autorenewPollKey)) ImmutableSet.of(oneTimeBillKey, recurringBillKey, autorenewPollKey))
.setServerApproveBillingEvent(oneTimeBillKey) .setServerApproveBillingEvent(oneTimeBillKey)
.setServerApproveAutorenewEvent(recurringBillKey) .setServerApproveAutorenewEvent(recurringBillKey)
@ -170,7 +219,7 @@ public class DomainBaseTest extends EntityTestCase {
.build()) .build())
.setDeletePollMessage(onetimePollKey) .setDeletePollMessage(onetimePollKey)
.setAutorenewBillingEvent(recurringBillKey) .setAutorenewBillingEvent(recurringBillKey)
.setAutorenewPollMessage(autorenewPollKey) .setAutorenewPollMessage(autorenewPollKey, historyEntry.getId())
.setSmdId("smdid") .setSmdId("smdid")
.addGracePeriod( .addGracePeriod(
GracePeriod.create( GracePeriod.create(
@ -200,19 +249,6 @@ public class DomainBaseTest extends EntityTestCase {
.hasValue(domain); .hasValue(domain);
} }
@Test
void testVKeyRestoration() {
assertThat(domain.deletePollMessageHistoryId).isEqualTo(domainHistory.getId());
assertThat(domain.autorenewBillingEventHistoryId).isEqualTo(domainHistory.getId());
assertThat(domain.autorenewPollMessageHistoryId).isEqualTo(domainHistory.getId());
assertThat(domain.getTransferData().getServerApproveBillingEventHistoryId())
.isEqualTo(domainHistory.getId());
assertThat(domain.getTransferData().getServerApproveAutorenewEventHistoryId())
.isEqualTo(domainHistory.getId());
assertThat(domain.getTransferData().getServerApproveAutorenewPollMessageHistoryId())
.isEqualTo(domainHistory.getId());
}
@Test @Test
void testEmptyStringsBecomeNull() { void testEmptyStringsBecomeNull() {
assertThat( assertThat(
@ -238,7 +274,6 @@ public class DomainBaseTest extends EntityTestCase {
.isNotNull(); .isNotNull();
} }
@Test
void testEmptySetsAndArraysBecomeNull() { void testEmptySetsAndArraysBecomeNull() {
assertThat( assertThat(
newDomainBase("example.com") newDomainBase("example.com")
@ -407,7 +442,10 @@ public class DomainBaseTest extends EntityTestCase {
.setPendingTransferExpirationTime(fakeClock.nowUtc().plusDays(1)) .setPendingTransferExpirationTime(fakeClock.nowUtc().plusDays(1))
.setGainingRegistrarId("TheRegistrar") .setGainingRegistrarId("TheRegistrar")
.setServerApproveBillingEvent(transferBillingEvent.createVKey()) .setServerApproveBillingEvent(transferBillingEvent.createVKey())
.setServerApproveEntities(ImmutableSet.of(transferBillingEvent.createVKey())) .setServerApproveEntities(
domain.getRepoId(),
historyEntry.getId(),
ImmutableSet.of(transferBillingEvent.createVKey()))
.build()) .build())
.addGracePeriod( .addGracePeriod(
// Okay for billing event to be null since the point of this grace period is just // Okay for billing event to be null since the point of this grace period is just

View file

@ -83,7 +83,7 @@ public class PollMessageExternalKeyConverterTest {
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(clock.nowUtc()) .setEventTime(clock.nowUtc())
.setMsg("Test poll message") .setMsg("Test poll message")
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.build()); .build());
assertThat(makePollMessageExternalId(pollMessage)).isEqualTo("1-2-FOOBAR-4-5-2007"); assertThat(makePollMessageExternalId(pollMessage)).isEqualTo("1-2-FOOBAR-4-5-2007");
assertVKeysEqual(parsePollMessageExternalId("1-2-FOOBAR-4-5-2007"), pollMessage.createVKey()); assertVKeysEqual(parsePollMessageExternalId("1-2-FOOBAR-4-5-2007"), pollMessage.createVKey());
@ -100,7 +100,7 @@ public class PollMessageExternalKeyConverterTest {
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(clock.nowUtc()) .setEventTime(clock.nowUtc())
.setMsg("Test poll message") .setMsg("Test poll message")
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.build()); .build());
assertThat(makePollMessageExternalId(pollMessage)).isEqualTo("2-5-ROID-6-7-2007"); assertThat(makePollMessageExternalId(pollMessage)).isEqualTo("2-5-ROID-6-7-2007");
assertVKeysEqual(parsePollMessageExternalId("2-5-ROID-6-7-2007"), pollMessage.createVKey()); assertVKeysEqual(parsePollMessageExternalId("2-5-ROID-6-7-2007"), pollMessage.createVKey());
@ -117,7 +117,7 @@ public class PollMessageExternalKeyConverterTest {
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(clock.nowUtc()) .setEventTime(clock.nowUtc())
.setMsg("Test poll message") .setMsg("Test poll message")
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.build()); .build());
assertThat(makePollMessageExternalId(pollMessage)).isEqualTo("3-5-ROID-6-7-2007"); assertThat(makePollMessageExternalId(pollMessage)).isEqualTo("3-5-ROID-6-7-2007");
assertVKeysEqual(parsePollMessageExternalId("3-5-ROID-6-7-2007"), pollMessage.createVKey()); assertVKeysEqual(parsePollMessageExternalId("3-5-ROID-6-7-2007"), pollMessage.createVKey());
@ -170,6 +170,5 @@ public class PollMessageExternalKeyConverterTest {
|| two.getKind().isAssignableFrom(one.getKind())) || two.getKind().isAssignableFrom(one.getKind()))
.isTrue(); .isTrue();
assertThat(one.getSqlKey()).isEqualTo(two.getSqlKey()); assertThat(one.getSqlKey()).isEqualTo(two.getSqlKey());
assertThat(one.getOfyKey()).isEqualTo(two.getOfyKey());
} }
} }

View file

@ -80,7 +80,7 @@ public class PollMessageTest extends EntityTestCase {
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(fakeClock.nowUtc()) .setEventTime(fakeClock.nowUtc())
.setMsg("Test poll message") .setMsg("Test poll message")
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.build(); .build();
autoRenew = autoRenew =
new PollMessage.Autorenew.Builder() new PollMessage.Autorenew.Builder()
@ -88,7 +88,7 @@ public class PollMessageTest extends EntityTestCase {
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(fakeClock.nowUtc()) .setEventTime(fakeClock.nowUtc())
.setMsg("Test poll message") .setMsg("Test poll message")
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.setAutorenewEndTime(fakeClock.nowUtc().plusDays(365)) .setAutorenewEndTime(fakeClock.nowUtc().plusDays(365))
.setTargetId("foobar.foo") .setTargetId("foobar.foo")
.build(); .build();
@ -116,7 +116,7 @@ public class PollMessageTest extends EntityTestCase {
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(fakeClock.nowUtc()) .setEventTime(fakeClock.nowUtc())
.setMsg("Test poll message") .setMsg("Test poll message")
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.build()); .build());
assertThat(tm().transact(() -> tm().loadByEntity(pollMessage))).isEqualTo(pollMessage); assertThat(tm().transact(() -> tm().loadByEntity(pollMessage))).isEqualTo(pollMessage);
} }
@ -135,16 +135,15 @@ public class PollMessageTest extends EntityTestCase {
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(fakeClock.nowUtc()) .setEventTime(fakeClock.nowUtc())
.setMsg("Test poll message") .setMsg("Test poll message")
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.setResponseData(ImmutableList.of(hostPendingActionNotificationResponse)) .setResponseData(ImmutableList.of(hostPendingActionNotificationResponse))
.build(); .build();
persistResource(pollMessage); persistResource(pollMessage);
assertThat(tm().transact(() -> tm().loadByEntity(pollMessage).getMsg())) assertThat(tm().transact(() -> tm().loadByEntity(pollMessage).getMsg()))
.isEqualTo(pollMessage.msg); .isEqualTo(pollMessage.msg);
assertThat( assertThat(
tm().transact(() -> tm().loadByEntity(pollMessage)) tm().transact(() -> tm().loadByEntity(pollMessage)).pendingActionNotificationResponse)
.hostPendingActionNotificationResponses) .isEqualTo(hostPendingActionNotificationResponse);
.contains(hostPendingActionNotificationResponse);
} }
@TestSqlOnly @TestSqlOnly
@ -155,7 +154,7 @@ public class PollMessageTest extends EntityTestCase {
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(fakeClock.nowUtc()) .setEventTime(fakeClock.nowUtc())
.setMsg("Test poll message") .setMsg("Test poll message")
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.build()); .build());
PollMessage persisted = tm().transact(() -> tm().loadByEntity(pollMessage)); PollMessage persisted = tm().transact(() -> tm().loadByEntity(pollMessage));
assertThat(SerializeUtils.serializeDeserialize(persisted)).isEqualTo(persisted); assertThat(SerializeUtils.serializeDeserialize(persisted)).isEqualTo(persisted);
@ -169,7 +168,7 @@ public class PollMessageTest extends EntityTestCase {
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(fakeClock.nowUtc()) .setEventTime(fakeClock.nowUtc())
.setMsg("Test poll message") .setMsg("Test poll message")
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.setAutorenewEndTime(fakeClock.nowUtc().plusDays(365)) .setAutorenewEndTime(fakeClock.nowUtc().plusDays(365))
.setTargetId("foobar.foo") .setTargetId("foobar.foo")
.build()); .build());
@ -184,7 +183,7 @@ public class PollMessageTest extends EntityTestCase {
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(fakeClock.nowUtc()) .setEventTime(fakeClock.nowUtc())
.setMsg("Test poll message") .setMsg("Test poll message")
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.setAutorenewEndTime(fakeClock.nowUtc().plusDays(365)) .setAutorenewEndTime(fakeClock.nowUtc().plusDays(365))
.setTargetId("foobar.foo") .setTargetId("foobar.foo")
.build()); .build());
@ -200,7 +199,7 @@ public class PollMessageTest extends EntityTestCase {
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(fakeClock.nowUtc()) .setEventTime(fakeClock.nowUtc())
.setMsg("Test poll message") .setMsg("Test poll message")
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.setAutorenewEndTime(fakeClock.nowUtc().plusDays(365)) .setAutorenewEndTime(fakeClock.nowUtc().plusDays(365))
.setTargetId("foobar.foo") .setTargetId("foobar.foo")
.build()); .build());

View file

@ -95,6 +95,8 @@ public class TransferDataTest {
.setPendingTransferExpirationTime(now) .setPendingTransferExpirationTime(now)
.setTransferStatus(TransferStatus.PENDING) .setTransferStatus(TransferStatus.PENDING)
.setServerApproveEntities( .setServerApproveEntities(
"4-TLD",
1356L,
ImmutableSet.of( ImmutableSet.of(
transferBillingEventKey, transferBillingEventKey,
otherServerApproveBillingEventKey, otherServerApproveBillingEventKey,

View file

@ -55,17 +55,10 @@ class DomainHistoryVKeyTest {
TestEntity persisted = tm().transact(() -> tm().loadByKey(original.createVKey())); TestEntity persisted = tm().transact(() -> tm().loadByKey(original.createVKey()));
assertThat(persisted).isEqualTo(original); assertThat(persisted).isEqualTo(original);
// Double check that the persisted.domainHistoryVKey is a symmetric VKey // Double check that the persisted.domainHistoryVKey is a symmetric VKey
assertThat(persisted.domainHistoryVKey.createOfyKey())
.isEqualTo(
Key.create(Key.create(DomainBase.class, "domainRepoId"), HistoryEntry.class, 10L));
assertThat(persisted.domainHistoryVKey.createSqlKey()) assertThat(persisted.domainHistoryVKey.createSqlKey())
.isEqualTo(new DomainHistoryId("domainRepoId", 10L)); .isEqualTo(new DomainHistoryId("domainRepoId", 10L));
assertThat(persisted.domainHistoryVKey.createVKey()) assertThat(persisted.domainHistoryVKey.createVKey())
.isEqualTo( .isEqualTo(VKey.createSql(HistoryEntry.class, new DomainHistoryId("domainRepoId", 10L)));
VKey.create(
HistoryEntry.class,
new DomainHistoryId("domainRepoId", 10L),
Key.create(Key.create(DomainBase.class, "domainRepoId"), HistoryEntry.class, 10L)));
} }
@TestOfyAndSql @TestOfyAndSql
@ -73,7 +66,6 @@ class DomainHistoryVKeyTest {
Key<HistoryEntry> ofyKey = Key<HistoryEntry> ofyKey =
Key.create(Key.create(DomainBase.class, "domainRepoId"), HistoryEntry.class, 10L); Key.create(Key.create(DomainBase.class, "domainRepoId"), HistoryEntry.class, 10L);
DomainHistoryVKey domainHistoryVKey = DomainHistoryVKey.create(ofyKey); DomainHistoryVKey domainHistoryVKey = DomainHistoryVKey.create(ofyKey);
assertThat(domainHistoryVKey.createOfyKey()).isEqualTo(ofyKey);
assertThat(domainHistoryVKey.createSqlKey()) assertThat(domainHistoryVKey.createSqlKey())
.isEqualTo(new DomainHistoryId("domainRepoId", 10L)); .isEqualTo(new DomainHistoryId("domainRepoId", 10L));
assertThat(domainHistoryVKey.createVKey()) assertThat(domainHistoryVKey.createVKey())

View file

@ -333,9 +333,10 @@ public class DomainBaseToXjcConverterTest {
.setEventTime(END_OF_TIME) .setEventTime(END_OF_TIME)
.setAutorenewEndTime(END_OF_TIME) .setAutorenewEndTime(END_OF_TIME)
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setParent(domainHistory) .setHistoryEntry(domainHistory)
.build()) .build())
.createVKey()) .createVKey(),
domainHistory.getId())
.setTransferData( .setTransferData(
new DomainTransferData.Builder() new DomainTransferData.Builder()
.setGainingRegistrarId("NewRegistrar") .setGainingRegistrarId("NewRegistrar")
@ -362,10 +363,13 @@ public class DomainBaseToXjcConverterTest {
.setEventTime(END_OF_TIME) .setEventTime(END_OF_TIME)
.setAutorenewEndTime(END_OF_TIME) .setAutorenewEndTime(END_OF_TIME)
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setParent(domainHistory) .setHistoryEntry(domainHistory)
.build()) .build())
.createVKey()) .createVKey())
.setServerApproveEntities(ImmutableSet.of(billingEvent.createVKey())) .setServerApproveEntities(
domain.getRepoId(),
domainHistory.getId(),
ImmutableSet.of(billingEvent.createVKey()))
.setTransferRequestTime(DateTime.parse("1919-01-01T00:00:00Z")) .setTransferRequestTime(DateTime.parse("1919-01-01T00:00:00Z"))
.setTransferStatus(TransferStatus.PENDING) .setTransferStatus(TransferStatus.PENDING)
.setTransferredRegistrationExpirationTime( .setTransferredRegistrationExpirationTime(

View file

@ -174,9 +174,10 @@ final class RdeFixtures {
.setEventTime(END_OF_TIME) .setEventTime(END_OF_TIME)
.setAutorenewEndTime(END_OF_TIME) .setAutorenewEndTime(END_OF_TIME)
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.build()) .build())
.createVKey()) .createVKey(),
historyEntry.getId())
.setTransferData( .setTransferData(
new DomainTransferData.Builder() new DomainTransferData.Builder()
.setGainingRegistrarId("gaining") .setGainingRegistrarId("gaining")
@ -203,10 +204,13 @@ final class RdeFixtures {
.setEventTime(END_OF_TIME) .setEventTime(END_OF_TIME)
.setAutorenewEndTime(END_OF_TIME) .setAutorenewEndTime(END_OF_TIME)
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.build()) .build())
.createVKey()) .createVKey())
.setServerApproveEntities(ImmutableSet.of(billingEvent.createVKey())) .setServerApproveEntities(
historyEntry.getDomainRepoId(),
historyEntry.getId(),
ImmutableSet.of(billingEvent.createVKey()))
.setTransferRequestTime(DateTime.parse("1991-01-01T00:00:00Z")) .setTransferRequestTime(DateTime.parse("1991-01-01T00:00:00Z"))
.setTransferStatus(TransferStatus.PENDING) .setTransferStatus(TransferStatus.PENDING)
.setTransferredRegistrationExpirationTime( .setTransferredRegistrationExpirationTime(

View file

@ -510,7 +510,7 @@ public class DatabaseHelper {
.setEventTime(expirationTime) .setEventTime(expirationTime)
.setMsg("Transfer server approved.") .setMsg("Transfer server approved.")
.setResponseData(ImmutableList.of(createTransferResponse(resource, transferData))) .setResponseData(ImmutableList.of(createTransferResponse(resource, transferData)))
.setParent(historyEntry) .setHistoryEntry(historyEntry)
.build(); .build();
} }
@ -549,6 +549,8 @@ public class DatabaseHelper {
createContactTransferDataBuilder(requestTime, expirationTime) createContactTransferDataBuilder(requestTime, expirationTime)
.setPendingTransferExpirationTime(now.plus(getContactAutomaticTransferLength())) .setPendingTransferExpirationTime(now.plus(getContactAutomaticTransferLength()))
.setServerApproveEntities( .setServerApproveEntities(
((ContactHistory) historyEntryContactTransfer).getContactRepoId(),
historyEntryContactTransfer.getId(),
ImmutableSet.of( ImmutableSet.of(
// Pretend it's 3 days since the request // Pretend it's 3 days since the request
persistResource( persistResource(
@ -630,13 +632,14 @@ public class DatabaseHelper {
.setEventTime(expirationTime) .setEventTime(expirationTime)
.setAutorenewEndTime(END_OF_TIME) .setAutorenewEndTime(END_OF_TIME)
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setParent(historyEntryDomainCreate) .setHistoryEntry(historyEntryDomainCreate)
.build()); .build());
return persistResource( return persistResource(
domain domain
.asBuilder() .asBuilder()
.setAutorenewBillingEvent(autorenewEvent.createVKey()) .setAutorenewBillingEvent(autorenewEvent.createVKey())
.setAutorenewPollMessage(autorenewPollMessage.createVKey()) .setAutorenewPollMessage(
autorenewPollMessage.createVKey(), autorenewPollMessage.getHistoryRevisionId())
.build()); .build());
} }
@ -676,7 +679,7 @@ public class DatabaseHelper {
.setEventTime(extendedRegistrationExpirationTime) .setEventTime(extendedRegistrationExpirationTime)
.setAutorenewEndTime(END_OF_TIME) .setAutorenewEndTime(END_OF_TIME)
.setMsg("Domain was auto-renewed.") .setMsg("Domain was auto-renewed.")
.setParent(historyEntryDomainTransfer) .setHistoryEntry(historyEntryDomainTransfer)
.build()); .build());
// Modify the existing autorenew event to reflect the pending transfer. // Modify the existing autorenew event to reflect the pending transfer.
persistResource( persistResource(
@ -711,6 +714,8 @@ public class DatabaseHelper {
.setServerApproveAutorenewPollMessage( .setServerApproveAutorenewPollMessage(
gainingClientAutorenewPollMessage.createVKey()) gainingClientAutorenewPollMessage.createVKey())
.setServerApproveEntities( .setServerApproveEntities(
historyEntryDomainTransfer.getDomainRepoId(),
historyEntryDomainTransfer.getId(),
ImmutableSet.of( ImmutableSet.of(
transferBillingEvent.createVKey(), transferBillingEvent.createVKey(),
gainingClientAutorenewEvent.createVKey(), gainingClientAutorenewEvent.createVKey(),
@ -887,9 +892,7 @@ public class DatabaseHelper {
return transactIfJpaTm( return transactIfJpaTm(
() -> () ->
tm().loadAllOf(PollMessage.class).stream() tm().loadAllOf(PollMessage.class).stream()
.filter( .filter(pollMessage -> pollMessage.getDomainRepoId().equals(domain.getRepoId()))
pollMessage ->
pollMessage.getParentKey().getParent().getName().equals(domain.getRepoId()))
.collect(toImmutableList())); .collect(toImmutableList()));
} }
@ -909,13 +912,7 @@ public class DatabaseHelper {
return transactIfJpaTm( return transactIfJpaTm(
() -> () ->
tm().loadAllOf(PollMessage.class).stream() tm().loadAllOf(PollMessage.class).stream()
.filter( .filter(pollMessage -> pollMessage.getDomainRepoId().equals(resource.getRepoId()))
pollMessage ->
pollMessage
.getParentKey()
.getParent()
.getName()
.equals(resource.getRepoId()))
.filter(pollMessage -> pollMessage.getRegistrarId().equals(registrarId)) .filter(pollMessage -> pollMessage.getRegistrarId().equals(registrarId))
.filter( .filter(
pollMessage -> pollMessage ->
@ -1176,7 +1173,14 @@ public class DatabaseHelper {
() -> () ->
tm().loadAllOf(PollMessage.class).stream() tm().loadAllOf(PollMessage.class).stream()
.filter( .filter(
pollMessage -> pollMessage.getParentKey().equals(Key.create(historyEntry))) pollMessage ->
pollMessage.getResourceName().equals(historyEntry.getParent().getName())
&& pollMessage.getHistoryRevisionId() == historyEntry.getId()
&& pollMessage
.getType()
.getResourceClass()
.getName()
.equals(historyEntry.getParent().getKind()))
.collect(toImmutableList()))); .collect(toImmutableList())));
} }

View file

@ -23,9 +23,9 @@ import static google.registry.testing.DatabaseHelper.newDomainBase;
import static google.registry.testing.DatabaseHelper.persistResource; import static google.registry.testing.DatabaseHelper.persistResource;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.googlecode.objectify.Key;
import google.registry.model.domain.DomainBase; import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory; import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.ofy.Ofy; import google.registry.model.ofy.Ofy;
import google.registry.model.poll.PollMessage; import google.registry.model.poll.PollMessage;
import google.registry.model.poll.PollMessage.Autorenew; import google.registry.model.poll.PollMessage.Autorenew;
@ -100,7 +100,7 @@ public class AckPollMessagesCommandTest extends CommandTestCase<AckPollMessagesC
persistResource( persistResource(
new PollMessage.Autorenew.Builder() new PollMessage.Autorenew.Builder()
.setId(625L) .setId(625L)
.setParentKey(domainHistory.createVKey().getOfyKey()) .setHistoryEntry(domainHistory)
.setEventTime(DateTime.parse("2011-04-15T22:33:44Z")) .setEventTime(DateTime.parse("2011-04-15T22:33:44Z"))
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setMsg("autorenew") .setMsg("autorenew")
@ -127,7 +127,7 @@ public class AckPollMessagesCommandTest extends CommandTestCase<AckPollMessagesC
persistResource( persistResource(
new PollMessage.Autorenew.Builder() new PollMessage.Autorenew.Builder()
.setId(625L) .setId(625L)
.setParentKey(domainHistory.createVKey().getOfyKey()) .setHistoryEntry(domainHistory)
.setEventTime(DateTime.parse("2011-04-15T22:33:44Z")) .setEventTime(DateTime.parse("2011-04-15T22:33:44Z"))
.setAutorenewEndTime(DateTime.parse("2012-01-01T22:33:44Z")) .setAutorenewEndTime(DateTime.parse("2012-01-01T22:33:44Z"))
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
@ -172,7 +172,7 @@ public class AckPollMessagesCommandTest extends CommandTestCase<AckPollMessagesC
persistResource( persistResource(
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setId(2474L) .setId(2474L)
.setParentKey(domainHistory.createVKey().getOfyKey()) .setHistoryEntry(domainHistory)
.setRegistrarId("NewRegistrar") .setRegistrarId("NewRegistrar")
.setEventTime(DateTime.parse("2013-06-01T22:33:44Z")) .setEventTime(DateTime.parse("2013-06-01T22:33:44Z"))
.setMsg("baaaahh") .setMsg("baaaahh")
@ -202,11 +202,7 @@ public class AckPollMessagesCommandTest extends CommandTestCase<AckPollMessagesC
return persistResource( return persistResource(
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setId(id) .setId(id)
.setParentKey( .setDomainHistoryId(new DomainHistoryId("FSDGS-TLD", domainHistory.getId()))
Key.create(
Key.create(DomainBase.class, "FSDGS-TLD"),
HistoryEntry.class,
domainHistory.getId()))
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(eventTime) .setEventTime(eventTime)
.setMsg(message) .setMsg(message)

View file

@ -75,7 +75,7 @@ class EnqueuePollMessageCommandTest extends CommandTestCase<EnqueuePollMessageCo
assertPollMessages( assertPollMessages(
"TheRegistrar", "TheRegistrar",
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setParent(synthetic) .setHistoryEntry(synthetic)
.setMsg("This domain is bad") .setMsg("This domain is bad")
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(fakeClock.nowUtc()) .setEventTime(fakeClock.nowUtc())
@ -107,7 +107,7 @@ class EnqueuePollMessageCommandTest extends CommandTestCase<EnqueuePollMessageCo
assertPollMessages( assertPollMessages(
"TheRegistrar", "TheRegistrar",
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setParent(synthetic) .setHistoryEntry(synthetic)
.setMsg("This domain needs work") .setMsg("This domain needs work")
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(fakeClock.nowUtc()) .setEventTime(fakeClock.nowUtc())
@ -115,7 +115,7 @@ class EnqueuePollMessageCommandTest extends CommandTestCase<EnqueuePollMessageCo
assertPollMessages( assertPollMessages(
"NewRegistrar", "NewRegistrar",
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setParent(synthetic) .setHistoryEntry(synthetic)
.setMsg("This domain needs work") .setMsg("This domain needs work")
.setRegistrarId("NewRegistrar") .setRegistrarId("NewRegistrar")
.setEventTime(fakeClock.nowUtc()) .setEventTime(fakeClock.nowUtc())
@ -123,7 +123,7 @@ class EnqueuePollMessageCommandTest extends CommandTestCase<EnqueuePollMessageCo
assertPollMessages( assertPollMessages(
"foobaz", "foobaz",
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setParent(synthetic) .setHistoryEntry(synthetic)
.setMsg("This domain needs work") .setMsg("This domain needs work")
.setRegistrarId("foobaz") .setRegistrarId("foobaz")
.setEventTime(fakeClock.nowUtc()) .setEventTime(fakeClock.nowUtc())
@ -152,7 +152,7 @@ class EnqueuePollMessageCommandTest extends CommandTestCase<EnqueuePollMessageCo
assertPollMessages( assertPollMessages(
"TheRegistrar", "TheRegistrar",
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setParent(synthetic) .setHistoryEntry(synthetic)
.setMsg("This domain needs work") .setMsg("This domain needs work")
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(fakeClock.nowUtc()) .setEventTime(fakeClock.nowUtc())
@ -160,7 +160,7 @@ class EnqueuePollMessageCommandTest extends CommandTestCase<EnqueuePollMessageCo
assertPollMessages( assertPollMessages(
"NewRegistrar", "NewRegistrar",
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setParent(synthetic) .setHistoryEntry(synthetic)
.setMsg("This domain needs work") .setMsg("This domain needs work")
.setRegistrarId("NewRegistrar") .setRegistrarId("NewRegistrar")
.setEventTime(fakeClock.nowUtc()) .setEventTime(fakeClock.nowUtc())
@ -168,7 +168,7 @@ class EnqueuePollMessageCommandTest extends CommandTestCase<EnqueuePollMessageCo
assertPollMessages( assertPollMessages(
"foobaz", "foobaz",
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setParent(synthetic) .setHistoryEntry(synthetic)
.setMsg("This domain needs work") .setMsg("This domain needs work")
.setRegistrarId("foobaz") .setRegistrarId("foobaz")
.setEventTime(fakeClock.nowUtc()) .setEventTime(fakeClock.nowUtc())

View file

@ -38,7 +38,7 @@ class GetDomainCommandTest extends CommandTestCase<GetDomainCommand> {
persistActiveDomain("example.tld"); persistActiveDomain("example.tld");
runCommand("example.tld"); runCommand("example.tld");
assertInStdout("fullyQualifiedDomainName=example.tld"); assertInStdout("fullyQualifiedDomainName=example.tld");
assertInStdout("contact=Key<?>(ContactResource(\"3-ROID\"))"); assertInStdout("Contact=VKey<ContactResource>(sql:3-ROID");
assertInStdout( assertInStdout(
"Websafe key: " "Websafe key: "
+ "kind:DomainBase" + "kind:DomainBase"
@ -51,7 +51,7 @@ class GetDomainCommandTest extends CommandTestCase<GetDomainCommand> {
persistActiveDomain("example.tld"); persistActiveDomain("example.tld");
runCommand("example.tld", "--expand"); runCommand("example.tld", "--expand");
assertInStdout("fullyQualifiedDomainName=example.tld"); assertInStdout("fullyQualifiedDomainName=example.tld");
assertInStdout("contact=Key<?>(ContactResource(\"3-ROID\"))"); assertInStdout("sqlKey=3-ROID");
assertInStdout( assertInStdout(
"Websafe key: " "Websafe key: "
+ "kind:DomainBase" + "kind:DomainBase"
@ -66,7 +66,7 @@ class GetDomainCommandTest extends CommandTestCase<GetDomainCommand> {
persistActiveDomain("xn--aualito-txac.xn--q9jyb4c"); persistActiveDomain("xn--aualito-txac.xn--q9jyb4c");
runCommand("çauçalito.みんな", "--expand"); runCommand("çauçalito.みんな", "--expand");
assertInStdout("fullyQualifiedDomainName=xn--aualito-txac.xn--q9jyb4c"); assertInStdout("fullyQualifiedDomainName=xn--aualito-txac.xn--q9jyb4c");
assertInStdout("contact=Key<?>(ContactResource(\"4-ROID\"))"); assertInStdout("sqlKey=4-ROID");
} }
@Test @Test

View file

@ -35,7 +35,6 @@ import static google.registry.testing.HistoryEntrySubject.assertAboutHistoryEntr
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import google.registry.model.billing.BillingEvent; import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Flag; import google.registry.model.billing.BillingEvent.Flag;
import google.registry.model.billing.BillingEvent.Reason; import google.registry.model.billing.BillingEvent.Reason;
@ -148,7 +147,7 @@ public class UnrenewDomainCommandTest extends CommandTestCase<UnrenewDomainComma
getPollMessages(domain), getPollMessages(domain),
ImmutableSet.of( ImmutableSet.of(
new PollMessage.OneTime.Builder() new PollMessage.OneTime.Builder()
.setParent(synthetic) .setHistoryEntry(synthetic)
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setMsg( .setMsg(
"Domain foo.tld was unrenewed by 2 years; " "Domain foo.tld was unrenewed by 2 years; "
@ -156,7 +155,7 @@ public class UnrenewDomainCommandTest extends CommandTestCase<UnrenewDomainComma
.setEventTime(unrenewTime) .setEventTime(unrenewTime)
.build(), .build(),
new PollMessage.Autorenew.Builder() new PollMessage.Autorenew.Builder()
.setParent(synthetic) .setHistoryEntry(synthetic)
.setTargetId("foo.tld") .setTargetId("foo.tld")
.setRegistrarId("TheRegistrar") .setRegistrarId("TheRegistrar")
.setEventTime(newExpirationTime) .setEventTime(newExpirationTime)
@ -164,8 +163,7 @@ public class UnrenewDomainCommandTest extends CommandTestCase<UnrenewDomainComma
.build())); .build()));
// Check that fields on domain were updated correctly. // Check that fields on domain were updated correctly.
assertThat(domain.getAutorenewPollMessage().getOfyKey().getParent()) assertThat(domain.getAutorenewPollMessageHistoryId()).isEqualTo(synthetic.getId());
.isEqualTo(Key.create(synthetic));
assertThat(domain.getRegistrationExpirationTime()).isEqualTo(newExpirationTime); assertThat(domain.getRegistrationExpirationTime()).isEqualTo(newExpirationTime);
assertThat(domain.getLastEppUpdateTime()).isEqualTo(unrenewTime); assertThat(domain.getLastEppUpdateTime()).isEqualTo(unrenewTime);
assertThat(domain.getLastEppUpdateRegistrarId()).isEqualTo("TheRegistrar"); assertThat(domain.getLastEppUpdateRegistrarId()).isEqualTo("TheRegistrar");

View file

@ -186,16 +186,6 @@ enum google.registry.model.contact.PostalInfo$Type {
INTERNATIONALIZED; INTERNATIONALIZED;
LOCALIZED; LOCALIZED;
} }
class google.registry.model.domain.DesignatedContact {
com.googlecode.objectify.Key<google.registry.model.contact.ContactResource> contact;
google.registry.model.domain.DesignatedContact$Type type;
}
enum google.registry.model.domain.DesignatedContact$Type {
ADMIN;
BILLING;
REGISTRANT;
TECH;
}
class google.registry.model.domain.DomainAuthInfo { class google.registry.model.domain.DomainAuthInfo {
google.registry.model.eppcommon.AuthInfo$PasswordAuth pw; google.registry.model.eppcommon.AuthInfo$PasswordAuth pw;
} }
@ -207,6 +197,10 @@ class google.registry.model.domain.DomainBase {
google.registry.model.domain.launch.LaunchNotice launchNotice; google.registry.model.domain.launch.LaunchNotice launchNotice;
google.registry.model.transfer.DomainTransferData transferData; google.registry.model.transfer.DomainTransferData transferData;
google.registry.persistence.VKey<google.registry.model.billing.BillingEvent$Recurring> autorenewBillingEvent; google.registry.persistence.VKey<google.registry.model.billing.BillingEvent$Recurring> autorenewBillingEvent;
google.registry.persistence.VKey<google.registry.model.contact.ContactResource> adminContact;
google.registry.persistence.VKey<google.registry.model.contact.ContactResource> billingContact;
google.registry.persistence.VKey<google.registry.model.contact.ContactResource> registrantContact;
google.registry.persistence.VKey<google.registry.model.contact.ContactResource> techContact;
google.registry.persistence.VKey<google.registry.model.poll.PollMessage$Autorenew> autorenewPollMessage; google.registry.persistence.VKey<google.registry.model.poll.PollMessage$Autorenew> autorenewPollMessage;
google.registry.persistence.VKey<google.registry.model.poll.PollMessage$OneTime> deletePollMessage; google.registry.persistence.VKey<google.registry.model.poll.PollMessage$OneTime> deletePollMessage;
java.lang.String creationClientId; java.lang.String creationClientId;
@ -216,7 +210,6 @@ class google.registry.model.domain.DomainBase {
java.lang.String lastEppUpdateClientId; java.lang.String lastEppUpdateClientId;
java.lang.String smdId; java.lang.String smdId;
java.lang.String tld; java.lang.String tld;
java.util.Set<google.registry.model.domain.DesignatedContact> allContacts;
java.util.Set<google.registry.model.domain.GracePeriod> gracePeriods; java.util.Set<google.registry.model.domain.GracePeriod> gracePeriods;
java.util.Set<google.registry.model.domain.secdns.DelegationSignerData> dsData; java.util.Set<google.registry.model.domain.secdns.DelegationSignerData> dsData;
java.util.Set<google.registry.model.eppcommon.StatusValue> status; java.util.Set<google.registry.model.eppcommon.StatusValue> status;
@ -236,6 +229,10 @@ class google.registry.model.domain.DomainContent {
google.registry.model.domain.launch.LaunchNotice launchNotice; google.registry.model.domain.launch.LaunchNotice launchNotice;
google.registry.model.transfer.DomainTransferData transferData; google.registry.model.transfer.DomainTransferData transferData;
google.registry.persistence.VKey<google.registry.model.billing.BillingEvent$Recurring> autorenewBillingEvent; google.registry.persistence.VKey<google.registry.model.billing.BillingEvent$Recurring> autorenewBillingEvent;
google.registry.persistence.VKey<google.registry.model.contact.ContactResource> adminContact;
google.registry.persistence.VKey<google.registry.model.contact.ContactResource> billingContact;
google.registry.persistence.VKey<google.registry.model.contact.ContactResource> registrantContact;
google.registry.persistence.VKey<google.registry.model.contact.ContactResource> techContact;
google.registry.persistence.VKey<google.registry.model.poll.PollMessage$Autorenew> autorenewPollMessage; google.registry.persistence.VKey<google.registry.model.poll.PollMessage$Autorenew> autorenewPollMessage;
google.registry.persistence.VKey<google.registry.model.poll.PollMessage$OneTime> deletePollMessage; google.registry.persistence.VKey<google.registry.model.poll.PollMessage$OneTime> deletePollMessage;
java.lang.String creationClientId; java.lang.String creationClientId;
@ -245,7 +242,6 @@ class google.registry.model.domain.DomainContent {
java.lang.String lastEppUpdateClientId; java.lang.String lastEppUpdateClientId;
java.lang.String smdId; java.lang.String smdId;
java.lang.String tld; java.lang.String tld;
java.util.Set<google.registry.model.domain.DesignatedContact> allContacts;
java.util.Set<google.registry.model.domain.GracePeriod> gracePeriods; java.util.Set<google.registry.model.domain.GracePeriod> gracePeriods;
java.util.Set<google.registry.model.domain.secdns.DelegationSignerData> dsData; java.util.Set<google.registry.model.domain.secdns.DelegationSignerData> dsData;
java.util.Set<google.registry.model.eppcommon.StatusValue> status; java.util.Set<google.registry.model.eppcommon.StatusValue> status;
@ -278,16 +274,16 @@ class google.registry.model.domain.DomainHistory {
} }
class google.registry.model.domain.GracePeriod { class google.registry.model.domain.GracePeriod {
google.registry.model.domain.rgp.GracePeriodStatus type; google.registry.model.domain.rgp.GracePeriodStatus type;
google.registry.persistence.BillingVKey$BillingEventVKey billingEventOneTime; google.registry.persistence.VKey<google.registry.model.billing.BillingEvent$OneTime> billingEventOneTime;
google.registry.persistence.BillingVKey$BillingRecurrenceVKey billingEventRecurring; google.registry.persistence.VKey<google.registry.model.billing.BillingEvent$Recurring> billingEventRecurring;
java.lang.String clientId; java.lang.String clientId;
long gracePeriodId; long gracePeriodId;
org.joda.time.DateTime expirationTime; org.joda.time.DateTime expirationTime;
} }
class google.registry.model.domain.GracePeriod$GracePeriodHistory { class google.registry.model.domain.GracePeriod$GracePeriodHistory {
google.registry.model.domain.rgp.GracePeriodStatus type; google.registry.model.domain.rgp.GracePeriodStatus type;
google.registry.persistence.BillingVKey$BillingEventVKey billingEventOneTime; google.registry.persistence.VKey<google.registry.model.billing.BillingEvent$OneTime> billingEventOneTime;
google.registry.persistence.BillingVKey$BillingRecurrenceVKey billingEventRecurring; google.registry.persistence.VKey<google.registry.model.billing.BillingEvent$Recurring> billingEventRecurring;
java.lang.Long domainHistoryRevisionId; java.lang.Long domainHistoryRevisionId;
java.lang.Long gracePeriodHistoryRevisionId; java.lang.Long gracePeriodHistoryRevisionId;
java.lang.String clientId; java.lang.String clientId;
@ -469,35 +465,14 @@ class google.registry.model.index.ForeignKeyIndex$ForeignKeyHostIndex {
google.registry.persistence.VKey<E> topReference; google.registry.persistence.VKey<E> topReference;
org.joda.time.DateTime deletionTime; org.joda.time.DateTime deletionTime;
} }
class google.registry.model.poll.PendingActionNotificationResponse$ContactPendingActionNotificationResponse {
google.registry.model.eppcommon.Trid trid;
google.registry.model.poll.PendingActionNotificationResponse$NameOrId nameOrId;
org.joda.time.DateTime processedDate;
}
class google.registry.model.poll.PendingActionNotificationResponse$DomainPendingActionNotificationResponse {
google.registry.model.eppcommon.Trid trid;
google.registry.model.poll.PendingActionNotificationResponse$NameOrId nameOrId;
org.joda.time.DateTime processedDate;
}
class google.registry.model.poll.PendingActionNotificationResponse$HostPendingActionNotificationResponse {
google.registry.model.eppcommon.Trid trid;
google.registry.model.poll.PendingActionNotificationResponse$NameOrId nameOrId;
org.joda.time.DateTime processedDate;
}
class google.registry.model.poll.PendingActionNotificationResponse$NameOrId {
boolean actionResult;
java.lang.String value;
}
class google.registry.model.poll.PollMessage { class google.registry.model.poll.PollMessage {
@Id java.lang.Long id; @Id java.lang.Long id;
@Parent com.googlecode.objectify.Key<? extends google.registry.model.reporting.HistoryEntry> parent;
java.lang.String clientId; java.lang.String clientId;
java.lang.String msg; java.lang.String msg;
org.joda.time.DateTime eventTime; org.joda.time.DateTime eventTime;
} }
class google.registry.model.poll.PollMessage$Autorenew { class google.registry.model.poll.PollMessage$Autorenew {
@Id java.lang.Long id; @Id java.lang.Long id;
@Parent com.googlecode.objectify.Key<? extends google.registry.model.reporting.HistoryEntry> parent;
java.lang.String clientId; java.lang.String clientId;
java.lang.String msg; java.lang.String msg;
java.lang.String targetId; java.lang.String targetId;
@ -506,14 +481,8 @@ class google.registry.model.poll.PollMessage$Autorenew {
} }
class google.registry.model.poll.PollMessage$OneTime { class google.registry.model.poll.PollMessage$OneTime {
@Id java.lang.Long id; @Id java.lang.Long id;
@Parent com.googlecode.objectify.Key<? extends google.registry.model.reporting.HistoryEntry> parent;
java.lang.String clientId; java.lang.String clientId;
java.lang.String msg; java.lang.String msg;
java.util.List<google.registry.model.poll.PendingActionNotificationResponse$ContactPendingActionNotificationResponse> contactPendingActionNotificationResponses;
java.util.List<google.registry.model.poll.PendingActionNotificationResponse$DomainPendingActionNotificationResponse> domainPendingActionNotificationResponses;
java.util.List<google.registry.model.poll.PendingActionNotificationResponse$HostPendingActionNotificationResponse> hostPendingActionNotificationResponses;
java.util.List<google.registry.model.transfer.TransferResponse$ContactTransferResponse> contactTransferResponses;
java.util.List<google.registry.model.transfer.TransferResponse$DomainTransferResponse> domainTransferResponses;
org.joda.time.DateTime eventTime; org.joda.time.DateTime eventTime;
} }
class google.registry.model.rde.RdeRevision { class google.registry.model.rde.RdeRevision {
@ -745,7 +714,6 @@ class google.registry.model.transfer.ContactTransferData {
google.registry.model.transfer.TransferStatus transferStatus; google.registry.model.transfer.TransferStatus transferStatus;
java.lang.String gainingClientId; java.lang.String gainingClientId;
java.lang.String losingClientId; java.lang.String losingClientId;
java.util.Set<google.registry.persistence.VKey<? extends google.registry.model.transfer.TransferData$TransferServerApproveEntity>> serverApproveEntities;
org.joda.time.DateTime pendingTransferExpirationTime; org.joda.time.DateTime pendingTransferExpirationTime;
org.joda.time.DateTime transferRequestTime; org.joda.time.DateTime transferRequestTime;
} }
@ -758,28 +726,10 @@ class google.registry.model.transfer.DomainTransferData {
google.registry.persistence.VKey<google.registry.model.poll.PollMessage$Autorenew> serverApproveAutorenewPollMessage; google.registry.persistence.VKey<google.registry.model.poll.PollMessage$Autorenew> serverApproveAutorenewPollMessage;
java.lang.String gainingClientId; java.lang.String gainingClientId;
java.lang.String losingClientId; java.lang.String losingClientId;
java.util.Set<google.registry.persistence.VKey<? extends google.registry.model.transfer.TransferData$TransferServerApproveEntity>> serverApproveEntities;
org.joda.time.DateTime pendingTransferExpirationTime; org.joda.time.DateTime pendingTransferExpirationTime;
org.joda.time.DateTime transferRequestTime; org.joda.time.DateTime transferRequestTime;
org.joda.time.DateTime transferredRegistrationExpirationTime; org.joda.time.DateTime transferredRegistrationExpirationTime;
} }
class google.registry.model.transfer.TransferResponse$ContactTransferResponse {
google.registry.model.transfer.TransferStatus transferStatus;
java.lang.String contactId;
java.lang.String gainingClientId;
java.lang.String losingClientId;
org.joda.time.DateTime pendingTransferExpirationTime;
org.joda.time.DateTime transferRequestTime;
}
class google.registry.model.transfer.TransferResponse$DomainTransferResponse {
google.registry.model.transfer.TransferStatus transferStatus;
java.lang.String fullyQualifiedDomainName;
java.lang.String gainingClientId;
java.lang.String losingClientId;
org.joda.time.DateTime extendedRegistrationExpirationTime;
org.joda.time.DateTime pendingTransferExpirationTime;
org.joda.time.DateTime transferRequestTime;
}
enum google.registry.model.transfer.TransferStatus { enum google.registry.model.transfer.TransferStatus {
CLIENT_APPROVED; CLIENT_APPROVED;
CLIENT_CANCELLED; CLIENT_CANCELLED;

View file

@ -265,13 +265,11 @@
auth_info_repo_id text, auth_info_repo_id text,
auth_info_value text, auth_info_value text,
billing_recurrence_id int8, billing_recurrence_id int8,
billing_recurrence_history_id int8,
autorenew_end_time timestamptz, autorenew_end_time timestamptz,
autorenew_poll_message_id int8, autorenew_poll_message_id int8,
autorenew_poll_message_history_id int8, autorenew_poll_message_history_id int8,
billing_contact text, billing_contact text,
deletion_poll_message_id int8, deletion_poll_message_id int8,
deletion_poll_message_history_id int8,
dns_refresh_request_time timestamptz, dns_refresh_request_time timestamptz,
domain_name text, domain_name text,
idn_table_name text, idn_table_name text,
@ -286,14 +284,11 @@
subordinate_hosts text[], subordinate_hosts text[],
tech_contact text, tech_contact text,
tld text, tld text,
transfer_billing_cancellation_history_id int8,
transfer_billing_cancellation_id int8, transfer_billing_cancellation_id int8,
transfer_billing_recurrence_id int8, transfer_billing_recurrence_id int8,
transfer_billing_recurrence_history_id int8,
transfer_autorenew_poll_message_id int8, transfer_autorenew_poll_message_id int8,
transfer_autorenew_poll_message_history_id int8, transfer_autorenew_poll_message_history_id int8,
transfer_billing_event_id int8, transfer_billing_event_id int8,
transfer_billing_event_history_id int8,
transfer_renew_period_unit text, transfer_renew_period_unit text,
transfer_renew_period_value int4, transfer_renew_period_value int4,
transfer_registration_expiration_time timestamptz, transfer_registration_expiration_time timestamptz,
@ -339,13 +334,11 @@
auth_info_repo_id text, auth_info_repo_id text,
auth_info_value text, auth_info_value text,
billing_recurrence_id int8, billing_recurrence_id int8,
billing_recurrence_history_id int8,
autorenew_end_time timestamptz, autorenew_end_time timestamptz,
autorenew_poll_message_id int8, autorenew_poll_message_id int8,
autorenew_poll_message_history_id int8, autorenew_poll_message_history_id int8,
billing_contact text, billing_contact text,
deletion_poll_message_id int8, deletion_poll_message_id int8,
deletion_poll_message_history_id int8,
dns_refresh_request_time timestamptz, dns_refresh_request_time timestamptz,
domain_name text, domain_name text,
idn_table_name text, idn_table_name text,
@ -360,14 +353,11 @@
subordinate_hosts text[], subordinate_hosts text[],
tech_contact text, tech_contact text,
tld text, tld text,
transfer_billing_cancellation_history_id int8,
transfer_billing_cancellation_id int8, transfer_billing_cancellation_id int8,
transfer_billing_recurrence_id int8, transfer_billing_recurrence_id int8,
transfer_billing_recurrence_history_id int8,
transfer_autorenew_poll_message_id int8, transfer_autorenew_poll_message_id int8,
transfer_autorenew_poll_message_history_id int8, transfer_autorenew_poll_message_history_id int8,
transfer_billing_event_id int8, transfer_billing_event_id int8,
transfer_billing_event_history_id int8,
transfer_renew_period_unit text, transfer_renew_period_unit text,
transfer_renew_period_value int4, transfer_renew_period_value int4,
transfer_registration_expiration_time timestamptz, transfer_registration_expiration_time timestamptz,
@ -422,11 +412,7 @@
create table "GracePeriod" ( create table "GracePeriod" (
grace_period_id int8 not null, grace_period_id int8 not null,
billing_event_id int8, billing_event_id int8,
billing_event_history_id int8,
billing_event_domain_repo_id text,
billing_recurrence_id int8, billing_recurrence_id int8,
billing_recurrence_history_id int8,
billing_recurrence_domain_repo_id text,
registrar_id text not null, registrar_id text not null,
domain_repo_id text not null, domain_repo_id text not null,
expiration_time timestamptz not null, expiration_time timestamptz not null,
@ -437,11 +423,7 @@
create table "GracePeriodHistory" ( create table "GracePeriodHistory" (
grace_period_history_revision_id int8 not null, grace_period_history_revision_id int8 not null,
billing_event_id int8, billing_event_id int8,
billing_event_history_id int8,
billing_event_domain_repo_id text,
billing_recurrence_id int8, billing_recurrence_id int8,
billing_recurrence_history_id int8,
billing_recurrence_domain_repo_id text,
registrar_id text not null, registrar_id text not null,
domain_repo_id text not null, domain_repo_id text not null,
expiration_time timestamptz not null, expiration_time timestamptz not null,

View file

@ -0,0 +1,50 @@
// Copyright 2022 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.util;
import com.google.common.collect.ImmutableCollection;
import javax.annotation.Nullable;
/**
* Collection builder that simply ignores requests to add null elements.
*
* <p>Useful because we do this in a number of cases.
*/
public class NullIgnoringCollectionBuilder<E, B extends ImmutableCollection.Builder<E>> {
private B builder;
private NullIgnoringCollectionBuilder(B builder) {
this.builder = builder;
}
public static <E2, B2 extends ImmutableCollection.Builder<E2>>
NullIgnoringCollectionBuilder<E2, B2> create(B2 builder) {
return new NullIgnoringCollectionBuilder<E2, B2>(builder);
}
/** If 'elem' is not null, add it to the builder. */
public NullIgnoringCollectionBuilder<E, B> add(@Nullable E elem) {
if (elem != null) {
builder.add(elem);
}
return this;
}
/** Returns the underlying builder. */
public B getBuilder() {
return builder;
}
}

View file

@ -0,0 +1,54 @@
// Copyright 2022 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.util;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.junit.jupiter.api.Test;
public class NullIgnoringCollectionBuilderTest {
public NullIgnoringCollectionBuilderTest() {}
@Test
public void testNullSafeCollections() {
assertThat(
NullIgnoringCollectionBuilder.create(new ImmutableList.Builder<Integer>())
.getBuilder()
.build())
.isEqualTo(ImmutableList.of());
assertThat(
NullIgnoringCollectionBuilder.create(new ImmutableList.Builder<Integer>())
.add(100)
.add(200)
.add(null)
.getBuilder()
.build())
.containsExactly(100, 200)
.inOrder();
assertThat(
NullIgnoringCollectionBuilder.create(new ImmutableSet.Builder<Integer>())
.add(100)
.add(200)
.add(null)
.getBuilder()
.build())
.containsExactly(100, 200);
}
}