mirror of
https://github.com/google/nomulus
synced 2026-09-18 22:14:23 +00:00
Convert DomainTransferRejectFlow to use tm() methods (#977)
* Convert DomainTransferRejectFlow to use tm() methods This change includes a few other necessary dependencies to converting DomainTransferRejectFlowTest to be a dual-database test. Namely: - The basic "use tm() instead of ofy()" and "branching database selection on what were previously raw ofy queries" - Modification of the PollMessage convertVKey methods to do what they say they do - Filling the generic pending / response fields in PollMessage based on what type of poll message it is (this has to be done because SQL is not very good at storing ambiguous superclasses) - Setting the generic pending / repsonse fields in PollMessage upon build - Filling out the serverApproveEntities field in DomainTransferData with all necessary poll messages / billing events that should be cancelled on rejection - Scattered changes in DatabaseHelper to make sure that we're saving and loading entities correctly where we weren't before
This commit is contained in:
@@ -18,12 +18,11 @@ import static com.google.common.collect.Sets.intersection;
|
||||
import static google.registry.model.EppResourceUtils.getLinkedDomainKeys;
|
||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
||||
import static google.registry.model.index.ForeignKeyIndex.loadAndGetKey;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.flows.EppException.AuthorizationErrorException;
|
||||
import google.registry.flows.EppException.InvalidAuthorizationInformationErrorException;
|
||||
import google.registry.flows.EppException.ObjectDoesNotExistException;
|
||||
@@ -185,16 +184,15 @@ public final class ResourceFlowUtils {
|
||||
return;
|
||||
}
|
||||
// The roid should match one of the contacts.
|
||||
Optional<Key<ContactResource>> foundContact =
|
||||
Optional<VKey<ContactResource>> foundContact =
|
||||
domain.getReferencedContacts().stream()
|
||||
.map(VKey::getOfyKey)
|
||||
.filter(key -> key.getName().equals(authRepoId))
|
||||
.filter(key -> key.getOfyKey().getName().equals(authRepoId))
|
||||
.findFirst();
|
||||
if (!foundContact.isPresent()) {
|
||||
throw new BadAuthInfoForResourceException();
|
||||
}
|
||||
// Check the authInfo against the contact.
|
||||
verifyAuthInfo(authInfo, ofy().load().key(foundContact.get()).now());
|
||||
verifyAuthInfo(authInfo, transactIfJpaTm(() -> tm().loadByKey(foundContact.get())));
|
||||
}
|
||||
|
||||
/** Check that the given {@link AuthInfo} is valid for the given contact. */
|
||||
|
||||
@@ -25,6 +25,9 @@ import static com.google.common.collect.Iterables.any;
|
||||
import static com.google.common.collect.Sets.difference;
|
||||
import static com.google.common.collect.Sets.intersection;
|
||||
import static com.google.common.collect.Sets.union;
|
||||
import static google.registry.model.DatabaseMigrationUtils.getPrimaryDatabase;
|
||||
import static google.registry.model.common.DatabaseTransitionSchedule.PrimaryDatabase.DATASTORE;
|
||||
import static google.registry.model.common.DatabaseTransitionSchedule.TransitionId.REPLAYED_ENTITIES;
|
||||
import static google.registry.model.domain.DomainBase.MAX_REGISTRATION_YEARS;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.model.registry.Registries.findTldForName;
|
||||
@@ -38,6 +41,7 @@ import static google.registry.model.registry.label.ReservationType.FULLY_BLOCKED
|
||||
import static google.registry.model.registry.label.ReservationType.NAME_COLLISION;
|
||||
import static google.registry.model.registry.label.ReservationType.RESERVED_FOR_ANCHOR_TENANT;
|
||||
import static google.registry.model.registry.label.ReservationType.RESERVED_FOR_SPECIFIC_USE;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.pricing.PricingEngineProxy.isDomainPremium;
|
||||
import static google.registry.util.CollectionUtils.nullToEmpty;
|
||||
@@ -88,6 +92,7 @@ import google.registry.model.domain.DomainCommand.Create;
|
||||
import google.registry.model.domain.DomainCommand.CreateOrUpdate;
|
||||
import google.registry.model.domain.DomainCommand.InvalidReferencesException;
|
||||
import google.registry.model.domain.DomainCommand.Update;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.domain.ForeignKeyedDesignatedContact;
|
||||
import google.registry.model.domain.Period;
|
||||
import google.registry.model.domain.fee.BaseFee;
|
||||
@@ -355,22 +360,23 @@ public class DomainFlowUtils {
|
||||
|
||||
static void validateNoDuplicateContacts(Set<DesignatedContact> contacts)
|
||||
throws ParameterValuePolicyErrorException {
|
||||
ImmutableMultimap<Type, Key<ContactResource>> contactsByType =
|
||||
ImmutableMultimap<Type, VKey<ContactResource>> contactsByType =
|
||||
contacts.stream()
|
||||
.collect(
|
||||
toImmutableSetMultimap(
|
||||
DesignatedContact::getType, contact -> contact.getContactKey().getOfyKey()));
|
||||
DesignatedContact::getType, contact -> contact.getContactKey()));
|
||||
|
||||
// If any contact type has multiple contacts:
|
||||
if (contactsByType.asMap().values().stream().anyMatch(v -> v.size() > 1)) {
|
||||
// Find the duplicates.
|
||||
Map<Type, Collection<Key<ContactResource>>> dupeKeysMap =
|
||||
Map<Type, Collection<VKey<ContactResource>>> dupeKeysMap =
|
||||
Maps.filterEntries(contactsByType.asMap(), e -> e.getValue().size() > 1);
|
||||
ImmutableList<Key<ContactResource>> dupeKeys =
|
||||
ImmutableList<VKey<ContactResource>> dupeKeys =
|
||||
dupeKeysMap.values().stream().flatMap(Collection::stream).collect(toImmutableList());
|
||||
// Load the duplicates in one batch.
|
||||
Map<Key<ContactResource>, ContactResource> dupeContacts = ofy().load().keys(dupeKeys);
|
||||
ImmutableMultimap.Builder<Type, Key<ContactResource>> typesMap =
|
||||
Map<VKey<? extends ContactResource>, ContactResource> dupeContacts =
|
||||
tm().loadByKeys(dupeKeys);
|
||||
ImmutableMultimap.Builder<Type, VKey<ContactResource>> typesMap =
|
||||
new ImmutableMultimap.Builder<>();
|
||||
dupeKeysMap.forEach(typesMap::putAll);
|
||||
// Create an error message showing the type and contact IDs of the duplicates.
|
||||
@@ -537,13 +543,13 @@ public class DomainFlowUtils {
|
||||
// If the resultant autorenew poll message would have no poll messages to deliver, then just
|
||||
// delete it. Otherwise save it with the new end time.
|
||||
if (isAtOrAfter(updatedAutorenewPollMessage.getEventTime(), newEndTime)) {
|
||||
autorenewPollMessage.ifPresent(autorenew -> ofy().delete().entity(autorenew));
|
||||
autorenewPollMessage.ifPresent(autorenew -> tm().delete(autorenew));
|
||||
} else {
|
||||
ofy().save().entity(updatedAutorenewPollMessage);
|
||||
tm().put(updatedAutorenewPollMessage);
|
||||
}
|
||||
|
||||
Recurring recurring = tm().loadByKey(domain.getAutorenewBillingEvent());
|
||||
ofy().save().entity(recurring.asBuilder().setRecurrenceEndTime(newEndTime).build());
|
||||
tm().put(recurring.asBuilder().setRecurrenceEndTime(newEndTime).build());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1045,18 +1051,11 @@ public class DomainFlowUtils {
|
||||
Duration maxSearchPeriod,
|
||||
final ImmutableSet<TransactionReportField> cancelableFields) {
|
||||
|
||||
List<HistoryEntry> recentHistoryEntries =
|
||||
ofy()
|
||||
.load()
|
||||
.type(HistoryEntry.class)
|
||||
.ancestor(domainBase)
|
||||
.filter("modificationTime >=", now.minus(maxSearchPeriod))
|
||||
.order("modificationTime")
|
||||
.list();
|
||||
Optional<HistoryEntry> entryToCancel =
|
||||
List<? extends HistoryEntry> recentHistoryEntries =
|
||||
findRecentHistoryEntries(domainBase, now, maxSearchPeriod);
|
||||
Optional<? extends HistoryEntry> entryToCancel =
|
||||
Streams.findLast(
|
||||
recentHistoryEntries
|
||||
.stream()
|
||||
recentHistoryEntries.stream()
|
||||
.filter(
|
||||
historyEntry -> {
|
||||
// Look for add and renew transaction records that have yet to be reported
|
||||
@@ -1082,6 +1081,28 @@ public class DomainFlowUtils {
|
||||
return recordsBuilder.build();
|
||||
}
|
||||
|
||||
private static List<? extends HistoryEntry> findRecentHistoryEntries(
|
||||
DomainBase domainBase, DateTime now, Duration maxSearchPeriod) {
|
||||
if (getPrimaryDatabase(REPLAYED_ENTITIES).equals(DATASTORE)) {
|
||||
return ofy()
|
||||
.load()
|
||||
.type(HistoryEntry.class)
|
||||
.ancestor(domainBase)
|
||||
.filter("modificationTime >=", now.minus(maxSearchPeriod))
|
||||
.order("modificationTime")
|
||||
.list();
|
||||
} else {
|
||||
return jpaTm()
|
||||
.getEntityManager()
|
||||
.createQuery(
|
||||
"FROM DomainHistory WHERE modificationTime >= :beginning "
|
||||
+ "ORDER BY modificationTime ASC",
|
||||
DomainHistory.class)
|
||||
.setParameter("beginning", now.minus(maxSearchPeriod))
|
||||
.getResultList();
|
||||
}
|
||||
}
|
||||
|
||||
/** Resource linked to this domain does not exist. */
|
||||
static class LinkedResourcesDoNotExistException extends ObjectDoesNotExistException {
|
||||
public LinkedResourcesDoNotExistException(Class<?> type, ImmutableSet<String> resourceIds) {
|
||||
|
||||
@@ -25,7 +25,6 @@ import static google.registry.flows.domain.DomainFlowUtils.updateAutorenewRecurr
|
||||
import static google.registry.flows.domain.DomainTransferUtils.createGainingTransferPollMessage;
|
||||
import static google.registry.flows.domain.DomainTransferUtils.createTransferResponse;
|
||||
import static google.registry.model.ResourceTransferUtils.denyPendingTransfer;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_NACKED;
|
||||
import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_SUCCESSFUL;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
@@ -41,7 +40,6 @@ import google.registry.flows.FlowModule.Superuser;
|
||||
import google.registry.flows.FlowModule.TargetId;
|
||||
import google.registry.flows.TransactionalFlow;
|
||||
import google.registry.flows.annotations.ReportingSpec;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.domain.metadata.MetadataExtension;
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
@@ -102,11 +100,11 @@ public final class DomainTransferRejectFlow implements TransactionalFlow {
|
||||
}
|
||||
DomainBase newDomain =
|
||||
denyPendingTransfer(existingDomain, TransferStatus.CLIENT_REJECTED, now, clientId);
|
||||
ofy().save().<ImmutableObject>entities(
|
||||
newDomain,
|
||||
historyEntry,
|
||||
createGainingTransferPollMessage(
|
||||
targetId, newDomain.getTransferData(), null, historyEntry));
|
||||
tm().putAll(
|
||||
newDomain,
|
||||
historyEntry,
|
||||
createGainingTransferPollMessage(
|
||||
targetId, newDomain.getTransferData(), null, historyEntry));
|
||||
// Reopen the autorenew event and poll message that we closed for the implicit transfer. This
|
||||
// may end up recreating the poll message if it was deleted upon the transfer request.
|
||||
updateAutorenewRecurrenceEndTime(existingDomain, END_OF_TIME);
|
||||
|
||||
@@ -118,9 +118,7 @@ public final class ResourceTransferUtils {
|
||||
if (resource.getStatusValues().contains(StatusValue.PENDING_TRANSFER)) {
|
||||
TransferData oldTransferData = resource.getTransferData();
|
||||
tm().delete(oldTransferData.getServerApproveEntities());
|
||||
ofy()
|
||||
.save()
|
||||
.entity(
|
||||
tm().put(
|
||||
new PollMessage.OneTime.Builder()
|
||||
.setClientId(oldTransferData.getGainingClientId())
|
||||
.setEventTime(now)
|
||||
|
||||
@@ -131,6 +131,11 @@ public class DatastoreTransactionManager implements TransactionManager {
|
||||
saveEntity(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Object... entities) {
|
||||
syncIfTransactionless(getOfy().save().entities(entities));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(ImmutableCollection<?> entities) {
|
||||
syncIfTransactionless(getOfy().save().entities(entities));
|
||||
|
||||
@@ -359,8 +359,13 @@ public abstract class PollMessage extends ImmutableObject
|
||||
}
|
||||
|
||||
/** Converts an unspecialized VKey<PollMessage> to a VKey of the derived class. */
|
||||
public static @Nullable VKey<OneTime> convertVKey(@Nullable VKey<OneTime> key) {
|
||||
return key == null ? null : VKey.create(OneTime.class, key.getSqlKey(), key.getOfyKey());
|
||||
public static @Nullable VKey<OneTime> convertVKey(@Nullable VKey<? extends PollMessage> key) {
|
||||
if (key == null) {
|
||||
return null;
|
||||
}
|
||||
Key<OneTime> ofyKey =
|
||||
Key.create(key.getOfyKey().getParent(), OneTime.class, key.getOfyKey().getId());
|
||||
return VKey.create(OneTime.class, key.getSqlKey(), ofyKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -383,6 +388,7 @@ public abstract class PollMessage extends ImmutableObject
|
||||
@OnLoad
|
||||
void onLoad() {
|
||||
super.onLoad();
|
||||
// Take the Objectify-specific fields and map them to the SQL-specific fields, if applicable
|
||||
if (!isNullOrEmpty(contactPendingActionNotificationResponses)) {
|
||||
pendingActionNotificationResponse = contactPendingActionNotificationResponses.get(0);
|
||||
}
|
||||
@@ -390,36 +396,70 @@ public abstract class PollMessage extends ImmutableObject
|
||||
contactId = contactTransferResponses.get(0).getContactId();
|
||||
transferResponse = contactTransferResponses.get(0);
|
||||
}
|
||||
if (!isNullOrEmpty(domainPendingActionNotificationResponses)) {
|
||||
pendingActionNotificationResponse = domainPendingActionNotificationResponses.get(0);
|
||||
}
|
||||
if (!isNullOrEmpty(domainTransferResponses)) {
|
||||
fullyQualifiedDomainName = domainTransferResponses.get(0).getFullyQualifiedDomainName();
|
||||
transferResponse = domainTransferResponses.get(0);
|
||||
extendedRegistrationExpirationTime =
|
||||
domainTransferResponses.get(0).getExtendedRegistrationExpirationTime();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@PostLoad
|
||||
void postLoad() {
|
||||
super.postLoad();
|
||||
// Take the SQL-specific fields and map them to the Objectify-specific fields, if applicable
|
||||
if (pendingActionNotificationResponse != null) {
|
||||
contactPendingActionNotificationResponses =
|
||||
ImmutableList.of(
|
||||
ContactPendingActionNotificationResponse.create(
|
||||
pendingActionNotificationResponse.nameOrId.value,
|
||||
pendingActionNotificationResponse.getActionResult(),
|
||||
pendingActionNotificationResponse.getTrid(),
|
||||
pendingActionNotificationResponse.processedDate));
|
||||
if (contactId != null) {
|
||||
contactPendingActionNotificationResponses =
|
||||
ImmutableList.of(
|
||||
ContactPendingActionNotificationResponse.create(
|
||||
pendingActionNotificationResponse.nameOrId.value,
|
||||
pendingActionNotificationResponse.getActionResult(),
|
||||
pendingActionNotificationResponse.getTrid(),
|
||||
pendingActionNotificationResponse.processedDate));
|
||||
} else if (fullyQualifiedDomainName != null) {
|
||||
domainPendingActionNotificationResponses =
|
||||
ImmutableList.of(
|
||||
DomainPendingActionNotificationResponse.create(
|
||||
pendingActionNotificationResponse.nameOrId.value,
|
||||
pendingActionNotificationResponse.getActionResult(),
|
||||
pendingActionNotificationResponse.getTrid(),
|
||||
pendingActionNotificationResponse.processedDate));
|
||||
}
|
||||
}
|
||||
if (contactId != null && transferResponse != null) {
|
||||
// The transferResponse is currently an unspecialized TransferResponse instance, create a
|
||||
// ContactTransferResponse so that the value is consistently specialized and store it in the
|
||||
// list representation for datastore.
|
||||
transferResponse =
|
||||
new ContactTransferResponse.Builder()
|
||||
.setContactId(contactId)
|
||||
.setGainingClientId(transferResponse.getGainingClientId())
|
||||
.setLosingClientId(transferResponse.getLosingClientId())
|
||||
.setTransferStatus(transferResponse.getTransferStatus())
|
||||
.setTransferRequestTime(transferResponse.getTransferRequestTime())
|
||||
.setPendingTransferExpirationTime(
|
||||
transferResponse.getPendingTransferExpirationTime())
|
||||
.build();
|
||||
contactTransferResponses = ImmutableList.of((ContactTransferResponse) transferResponse);
|
||||
if (transferResponse != null) {
|
||||
// The transferResponse is currently an unspecialized TransferResponse instance, create the
|
||||
// appropriate subclass so that the value is consistently specialized
|
||||
if (contactId != null) {
|
||||
transferResponse =
|
||||
new ContactTransferResponse.Builder()
|
||||
.setContactId(contactId)
|
||||
.setGainingClientId(transferResponse.getGainingClientId())
|
||||
.setLosingClientId(transferResponse.getLosingClientId())
|
||||
.setTransferStatus(transferResponse.getTransferStatus())
|
||||
.setTransferRequestTime(transferResponse.getTransferRequestTime())
|
||||
.setPendingTransferExpirationTime(
|
||||
transferResponse.getPendingTransferExpirationTime())
|
||||
.build();
|
||||
contactTransferResponses = ImmutableList.of((ContactTransferResponse) transferResponse);
|
||||
} else if (fullyQualifiedDomainName != null) {
|
||||
transferResponse =
|
||||
new DomainTransferResponse.Builder()
|
||||
.setFullyQualifiedDomainName(fullyQualifiedDomainName)
|
||||
.setGainingClientId(transferResponse.getGainingClientId())
|
||||
.setLosingClientId(transferResponse.getLosingClientId())
|
||||
.setTransferStatus(transferResponse.getTransferStatus())
|
||||
.setTransferRequestTime(transferResponse.getTransferRequestTime())
|
||||
.setPendingTransferExpirationTime(
|
||||
transferResponse.getPendingTransferExpirationTime())
|
||||
.setExtendedRegistrationExpirationTime(extendedRegistrationExpirationTime)
|
||||
.build();
|
||||
domainTransferResponses = ImmutableList.of((DomainTransferResponse) transferResponse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,10 +481,7 @@ public abstract class PollMessage extends ImmutableObject
|
||||
.filter(ContactPendingActionNotificationResponse.class::isInstance)
|
||||
.map(ContactPendingActionNotificationResponse.class::cast)
|
||||
.collect(toImmutableList()));
|
||||
if (getInstance().contactPendingActionNotificationResponses != null) {
|
||||
getInstance().pendingActionNotificationResponse =
|
||||
getInstance().contactPendingActionNotificationResponses.get(0);
|
||||
}
|
||||
|
||||
getInstance().contactTransferResponses =
|
||||
forceEmptyToNull(
|
||||
responseData
|
||||
@@ -452,10 +489,6 @@ public abstract class PollMessage extends ImmutableObject
|
||||
.filter(ContactTransferResponse.class::isInstance)
|
||||
.map(ContactTransferResponse.class::cast)
|
||||
.collect(toImmutableList()));
|
||||
if (getInstance().contactTransferResponses != null) {
|
||||
getInstance().contactId = getInstance().contactTransferResponses.get(0).getContactId();
|
||||
getInstance().transferResponse = getInstance().contactTransferResponses.get(0);
|
||||
}
|
||||
|
||||
getInstance().domainPendingActionNotificationResponses =
|
||||
forceEmptyToNull(
|
||||
@@ -471,13 +504,36 @@ public abstract class PollMessage extends ImmutableObject
|
||||
.filter(DomainTransferResponse.class::isInstance)
|
||||
.map(DomainTransferResponse.class::cast)
|
||||
.collect(toImmutableList()));
|
||||
|
||||
getInstance().hostPendingActionNotificationResponses =
|
||||
forceEmptyToNull(
|
||||
responseData
|
||||
.stream()
|
||||
responseData.stream()
|
||||
.filter(HostPendingActionNotificationResponse.class::isInstance)
|
||||
.map(HostPendingActionNotificationResponse.class::cast)
|
||||
.collect(toImmutableList()));
|
||||
|
||||
// Set the generic pending-action field as appropriate
|
||||
if (getInstance().contactPendingActionNotificationResponses != null) {
|
||||
getInstance().pendingActionNotificationResponse =
|
||||
getInstance().contactPendingActionNotificationResponses.get(0);
|
||||
} else if (getInstance().domainPendingActionNotificationResponses != null) {
|
||||
getInstance().pendingActionNotificationResponse =
|
||||
getInstance().domainPendingActionNotificationResponses.get(0);
|
||||
} else if (getInstance().hostPendingActionNotificationResponses != null) {
|
||||
getInstance().pendingActionNotificationResponse =
|
||||
getInstance().hostPendingActionNotificationResponses.get(0);
|
||||
}
|
||||
// Set the generic transfer response field as appropriate
|
||||
if (getInstance().contactTransferResponses != null) {
|
||||
getInstance().contactId = getInstance().contactTransferResponses.get(0).getContactId();
|
||||
getInstance().transferResponse = getInstance().contactTransferResponses.get(0);
|
||||
} else if (getInstance().domainTransferResponses != null) {
|
||||
getInstance().fullyQualifiedDomainName =
|
||||
getInstance().domainTransferResponses.get(0).getFullyQualifiedDomainName();
|
||||
getInstance().transferResponse = getInstance().domainTransferResponses.get(0);
|
||||
getInstance().extendedRegistrationExpirationTime =
|
||||
getInstance().domainTransferResponses.get(0).getExtendedRegistrationExpirationTime();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -518,8 +574,13 @@ public abstract class PollMessage extends ImmutableObject
|
||||
}
|
||||
|
||||
/** Converts an unspecialized VKey<PollMessage> to a VKey of the derived class. */
|
||||
public static @Nullable VKey<Autorenew> convertVKey(VKey<Autorenew> key) {
|
||||
return key == null ? null : VKey.create(Autorenew.class, key.getSqlKey(), key.getOfyKey());
|
||||
public static @Nullable VKey<Autorenew> convertVKey(VKey<? extends PollMessage> key) {
|
||||
if (key == null) {
|
||||
return null;
|
||||
}
|
||||
Key<Autorenew> ofyKey =
|
||||
Key.create(key.getOfyKey().getParent(), Autorenew.class, key.getOfyKey().getId());
|
||||
return VKey.create(Autorenew.class, key.getSqlKey(), ofyKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -14,7 +14,10 @@
|
||||
|
||||
package google.registry.model.transfer;
|
||||
|
||||
import static google.registry.util.CollectionUtils.forceEmptyToNull;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.AlsoLoad;
|
||||
import com.googlecode.objectify.annotation.Embed;
|
||||
@@ -34,6 +37,7 @@ import javax.persistence.AttributeOverrides;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.PostLoad;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** Transfer data for domain. */
|
||||
@@ -214,6 +218,28 @@ public class DomainTransferData extends TransferData<DomainTransferData.Builder>
|
||||
return serverApproveAutorenewPollMessageHistoryId;
|
||||
}
|
||||
|
||||
@PostLoad
|
||||
@Override
|
||||
void postLoad() {
|
||||
// The superclass's serverApproveEntities should include the billing events if present
|
||||
super.postLoad();
|
||||
ImmutableSet.Builder<VKey<? extends TransferServerApproveEntity>> serverApproveEntitiesBuilder =
|
||||
new ImmutableSet.Builder<>();
|
||||
if (serverApproveEntities != null) {
|
||||
serverApproveEntitiesBuilder.addAll(serverApproveEntities);
|
||||
}
|
||||
if (serverApproveBillingEvent != null) {
|
||||
serverApproveEntitiesBuilder.add(serverApproveBillingEvent);
|
||||
}
|
||||
if (serverApproveAutorenewEvent != null) {
|
||||
serverApproveEntitiesBuilder.add(serverApproveAutorenewEvent);
|
||||
}
|
||||
if (serverApproveAutorenewPollMessage != null) {
|
||||
serverApproveEntitiesBuilder.add(serverApproveAutorenewPollMessage);
|
||||
}
|
||||
serverApproveEntities = forceEmptyToNull(serverApproveEntitiesBuilder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return EMPTY.equals(this);
|
||||
|
||||
@@ -167,7 +167,7 @@ public abstract class TransferData<
|
||||
return;
|
||||
}
|
||||
Key<? extends EppResource> eppKey;
|
||||
if (getClass().equals(DomainBase.class)) {
|
||||
if (getClass().equals(DomainTransferData.class)) {
|
||||
eppKey = Key.create(DomainBase.class, repoId);
|
||||
} else {
|
||||
eppKey = Key.create(ContactResource.class, repoId);
|
||||
|
||||
+9
@@ -288,6 +288,15 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
|
||||
transactionInfo.get().addUpdate(toPersist);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Object... entities) {
|
||||
checkArgumentNotNull(entities, "entities must be specified");
|
||||
assertInTransaction();
|
||||
for (Object entity : entities) {
|
||||
put(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(ImmutableCollection<?> entities) {
|
||||
checkArgumentNotNull(entities, "entities must be specified");
|
||||
|
||||
@@ -123,7 +123,10 @@ public interface TransactionManager {
|
||||
/** Persists a new entity or update the existing entity in the database. */
|
||||
void put(Object entity);
|
||||
|
||||
/** Persists all new entities or update the existing entities in the database. */
|
||||
/** Persists all new entities or updates the existing entities in the database. */
|
||||
void putAll(Object... entities);
|
||||
|
||||
/** Persists all new entities or updates the existing entities in the database. */
|
||||
void putAll(ImmutableCollection<?> entities);
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user