1
0
mirror of https://github.com/google/nomulus synced 2026-02-09 14:30:33 +00:00

Refactor TransferData to remove unused fields in Contact table (#623)

* Add DomainTransferData and ContactTransferData

* Refactor TransferData to remove unused fields in Contact table

* Add scope for TransferData's type parameter
This commit is contained in:
Shicong Huang
2020-06-16 10:42:57 -04:00
committed by GitHub
parent 21f2f38ad1
commit 26e2a51180
38 changed files with 491 additions and 324 deletions

View File

@@ -46,7 +46,7 @@ import google.registry.model.eppoutput.EppResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.ContactTransferData;
import google.registry.model.transfer.TransferStatus;
import java.util.Optional;
import javax.inject.Inject;
@@ -112,21 +112,22 @@ public final class ContactTransferRequestFlow implements TransactionalFlow {
.setParent(Key.create(existingContact))
.build();
DateTime transferExpirationTime = now.plus(automaticTransferLength);
TransferData serverApproveTransferData = new TransferData.Builder()
.setTransferRequestTime(now)
.setTransferRequestTrid(trid)
.setGainingClientId(gainingClientId)
.setLosingClientId(losingClientId)
.setPendingTransferExpirationTime(transferExpirationTime)
.setTransferStatus(TransferStatus.SERVER_APPROVED)
.build();
ContactTransferData serverApproveTransferData =
new ContactTransferData.Builder()
.setTransferRequestTime(now)
.setTransferRequestTrid(trid)
.setGainingClientId(gainingClientId)
.setLosingClientId(losingClientId)
.setPendingTransferExpirationTime(transferExpirationTime)
.setTransferStatus(TransferStatus.SERVER_APPROVED)
.build();
// If the transfer is server approved, this message will be sent to the losing registrar. */
PollMessage serverApproveLosingPollMessage =
createLosingTransferPollMessage(targetId, serverApproveTransferData, historyEntry);
// If the transfer is server approved, this message will be sent to the gaining registrar. */
PollMessage serverApproveGainingPollMessage =
createGainingTransferPollMessage(targetId, serverApproveTransferData, historyEntry);
TransferData pendingTransferData =
ContactTransferData pendingTransferData =
serverApproveTransferData
.asBuilder()
.setTransferStatus(TransferStatus.PENDING)

View File

@@ -58,7 +58,7 @@ import google.registry.model.registry.Registry;
import google.registry.model.reporting.DomainTransactionRecord;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferStatus;
import java.util.Optional;
import javax.inject.Inject;
@@ -112,7 +112,7 @@ public final class DomainTransferApproveFlow implements TransactionalFlow {
if (!isSuperuser) {
checkAllowedAccessToTld(clientId, tld);
}
TransferData transferData = existingDomain.getTransferData();
DomainTransferData transferData = existingDomain.getTransferData();
String gainingClientId = transferData.getGainingClientId();
Registry registry = Registry.get(existingDomain.getTld());
HistoryEntry historyEntry = buildHistoryEntry(existingDomain, registry, now, gainingClientId);

View File

@@ -32,7 +32,7 @@ import google.registry.model.domain.DomainBase;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppoutput.EppResponse;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferStatus;
import google.registry.util.Clock;
import java.util.Optional;
@@ -74,7 +74,7 @@ public final class DomainTransferQueryFlow implements Flow {
verifyOptionalAuthInfo(authInfo, domain);
// Most of the fields on the transfer response are required, so there's no way to return valid
// XML if the object has never been transferred (and hence the fields aren't populated).
TransferData transferData = domain.getTransferData();
DomainTransferData transferData = domain.getTransferData();
if (transferData.getTransferStatus() == null) {
throw new NoTransferHistoryToQueryException();
}

View File

@@ -69,7 +69,7 @@ import google.registry.model.reporting.DomainTransactionRecord;
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferData.TransferServerApproveEntity;
import google.registry.model.transfer.TransferResponse.DomainTransferResponse;
import google.registry.model.transfer.TransferStatus;
@@ -198,9 +198,9 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
feesAndCredits.map(FeesAndCredits::getTotalCost),
now);
// Create the transfer data that represents the pending transfer.
TransferData pendingTransferData =
DomainTransferData pendingTransferData =
createPendingTransferData(
new TransferData.Builder()
new DomainTransferData.Builder()
.setTransferRequestTrid(trid)
.setTransferRequestTime(now)
.setGainingClientId(gainingClientId)

View File

@@ -32,6 +32,7 @@ import google.registry.model.poll.PendingActionNotificationResponse.DomainPendin
import google.registry.model.poll.PollMessage;
import google.registry.model.registry.Registry;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferData.TransferServerApproveEntity;
import google.registry.model.transfer.TransferResponse.DomainTransferResponse;
@@ -48,8 +49,8 @@ import org.joda.time.DateTime;
public final class DomainTransferUtils {
/** Sets up {@link TransferData} for a domain with links to entities for server approval. */
public static TransferData createPendingTransferData(
TransferData.Builder transferDataBuilder,
public static DomainTransferData createPendingTransferData(
DomainTransferData.Builder transferDataBuilder,
ImmutableSet<TransferServerApproveEntity> serverApproveEntities,
Period transferPeriod) {
ImmutableSet.Builder<VKey<? extends TransferServerApproveEntity>> serverApproveEntityKeys =
@@ -110,8 +111,8 @@ public final class DomainTransferUtils {
DateTime now) {
String targetId = existingDomain.getFullyQualifiedDomainName();
// Create a TransferData for the server-approve case to use for the speculative poll messages.
TransferData serverApproveTransferData =
new TransferData.Builder()
DomainTransferData serverApproveTransferData =
new DomainTransferData.Builder()
.setTransferRequestTrid(trid)
.setTransferRequestTime(now)
.setGainingClientId(gainingClientId)

View File

@@ -193,8 +193,8 @@ public abstract class EppResource extends BackupGroupRoot implements Buildable {
public interface ForeignKeyedEppResource {}
/** An interface for resources that have transfer data. */
public interface ResourceWithTransferData {
TransferData getTransferData();
public interface ResourceWithTransferData<T extends TransferData> {
T getTransferData();
/**
* The time that this resource was last transferred.
@@ -205,8 +205,9 @@ public abstract class EppResource extends BackupGroupRoot implements Buildable {
}
/** An interface for builders of resources that have transfer data. */
public interface BuilderWithTransferData<B extends BuilderWithTransferData<B>> {
B setTransferData(TransferData transferData);
public interface BuilderWithTransferData<
T extends TransferData, B extends BuilderWithTransferData<T, B>> {
B setTransferData(T transferData);
/** Set the time when this resource was transferred. */
B setLastTransferTime(DateTime lastTransferTime);

View File

@@ -39,6 +39,7 @@ import google.registry.model.index.ForeignKeyIndex;
import google.registry.model.ofy.CommitLogManifest;
import google.registry.model.ofy.CommitLogMutation;
import google.registry.model.registry.Registry;
import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferStatus;
import java.util.List;
@@ -222,17 +223,23 @@ public final class EppResourceUtils {
}
/** Process an automatic transfer on a resource. */
public static <B extends EppResource.Builder<?, B> & BuilderWithTransferData<B>>
public static <
T extends TransferData,
B extends EppResource.Builder<?, B> & BuilderWithTransferData<T, B>>
void setAutomaticTransferSuccessProperties(B builder, TransferData transferData) {
checkArgument(TransferStatus.PENDING.equals(transferData.getTransferStatus()));
builder.removeStatusValue(StatusValue.PENDING_TRANSFER)
.setTransferData(transferData.asBuilder()
.setTransferStatus(TransferStatus.SERVER_APPROVED)
.setServerApproveEntities(null)
.setServerApproveBillingEvent(null)
.setServerApproveAutorenewEvent(null)
.setServerApproveAutorenewPollMessage(null)
.build())
TransferData.Builder transferDataBuilder = transferData.asBuilder();
transferDataBuilder.setTransferStatus(TransferStatus.SERVER_APPROVED);
transferDataBuilder.setServerApproveEntities(null);
if (transferData instanceof DomainTransferData) {
((DomainTransferData.Builder) transferDataBuilder)
.setServerApproveBillingEvent(null)
.setServerApproveAutorenewEvent(null)
.setServerApproveAutorenewPollMessage(null);
}
builder
.removeStatusValue(StatusValue.PENDING_TRANSFER)
.setTransferData((T) transferDataBuilder.build())
.setLastTransferTime(transferData.getPendingTransferExpirationTime())
.setPersistedCurrentSponsorClientId(transferData.getGainingClientId());
}
@@ -245,10 +252,11 @@ public final class EppResourceUtils {
* </ul>
*/
public static <
T extends EppResource & ResourceWithTransferData,
B extends EppResource.Builder<?, B> & BuilderWithTransferData<B>>
void projectResourceOntoBuilderAtTime(T resource, B builder, DateTime now) {
TransferData transferData = resource.getTransferData();
T extends TransferData,
E extends EppResource & ResourceWithTransferData<T>,
B extends EppResource.Builder<?, B> & BuilderWithTransferData<T, B>>
void projectResourceOntoBuilderAtTime(E resource, B builder, DateTime now) {
T transferData = resource.getTransferData();
// If there's a pending transfer that has expired, process it.
DateTime expirationTime = transferData.getPendingTransferExpirationTime();
if (TransferStatus.PENDING.equals(transferData.getTransferStatus())

View File

@@ -36,6 +36,7 @@ import google.registry.model.poll.PendingActionNotificationResponse.ContactPendi
import google.registry.model.poll.PendingActionNotificationResponse.DomainPendingActionNotificationResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferResponse;
import google.registry.model.transfer.TransferResponse.ContactTransferResponse;
@@ -63,12 +64,13 @@ public final class ResourceTransferUtils {
if (eppResource instanceof ContactResource) {
builder = new ContactTransferResponse.Builder().setContactId(eppResource.getForeignKey());
} else {
DomainTransferData domainTransferData = (DomainTransferData) transferData;
builder =
new DomainTransferResponse.Builder()
.setFullyQualifiedDomainName(eppResource.getForeignKey())
.setExtendedRegistrationExpirationTime(
ADD_EXDATE_STATUSES.contains(transferData.getTransferStatus())
? transferData.getTransferredRegistrationExpirationTime()
ADD_EXDATE_STATUSES.contains(domainTransferData.getTransferStatus())
? domainTransferData.getTransferredRegistrationExpirationTime()
: null);
}
builder.setGainingClientId(transferData.getGainingClientId())
@@ -142,23 +144,25 @@ public final class ResourceTransferUtils {
*/
private static <
R extends EppResource & ResourceWithTransferData,
B extends EppResource.Builder<R, B> & BuilderWithTransferData<B>>
B extends EppResource.Builder<R, B> & BuilderWithTransferData<TransferData, B>>
B resolvePendingTransfer(R resource, TransferStatus transferStatus, DateTime now) {
checkArgument(
resource.getStatusValues().contains(StatusValue.PENDING_TRANSFER),
"Resource is not in pending transfer status.");
checkArgument(
!TransferData.EMPTY.equals(resource.getTransferData()),
"No old transfer data to resolve.");
checkArgument(!resource.getTransferData().isEmpty(), "No old transfer data to resolve.");
@SuppressWarnings("unchecked")
B builder = (B) resource.asBuilder();
return builder
.removeStatusValue(StatusValue.PENDING_TRANSFER)
.setTransferData(
resource.getTransferData().copyConstantFieldsToBuilder()
.setTransferStatus(transferStatus)
.setPendingTransferExpirationTime(checkNotNull(now))
.build());
(TransferData)
resource
.getTransferData()
.copyConstantFieldsToBuilder()
.setTransferStatus(transferStatus)
.setPendingTransferExpirationTime(checkNotNull(now))
.build());
}
/**
@@ -171,7 +175,7 @@ public final class ResourceTransferUtils {
*/
public static <
R extends EppResource & ResourceWithTransferData,
B extends EppResource.Builder<R, B> & BuilderWithTransferData<B>>
B extends EppResource.Builder<R, B> & BuilderWithTransferData<TransferData, B>>
R approvePendingTransfer(R resource, TransferStatus transferStatus, DateTime now) {
checkArgument(transferStatus.isApproved(), "Not an approval transfer status");
B builder = resolvePendingTransfer(resource, transferStatus, now);

View File

@@ -30,7 +30,7 @@ import google.registry.model.EppResource.ResourceWithTransferData;
import google.registry.model.annotations.ExternalMessagingName;
import google.registry.model.annotations.ReportedOn;
import google.registry.model.contact.PostalInfo.Type;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.ContactTransferData;
import google.registry.persistence.VKey;
import google.registry.persistence.WithStringVKey;
import google.registry.schema.replay.DatastoreAndSqlEntity;
@@ -170,7 +170,7 @@ public class ContactResource extends EppResource
ContactAuthInfo authInfo;
/** Data about any pending or past transfers on this contact. */
TransferData transferData;
ContactTransferData transferData;
/**
* The time that this resource was last transferred.
@@ -242,8 +242,8 @@ public class ContactResource extends EppResource
}
@Override
public final TransferData getTransferData() {
return Optional.ofNullable(transferData).orElse(TransferData.EMPTY);
public final ContactTransferData getTransferData() {
return Optional.ofNullable(transferData).orElse(ContactTransferData.EMPTY);
}
@Override
@@ -285,7 +285,7 @@ public class ContactResource extends EppResource
/** A builder for constructing {@link ContactResource}, since it is immutable. */
public static class Builder extends EppResource.Builder<ContactResource, Builder>
implements BuilderWithTransferData<Builder> {
implements BuilderWithTransferData<ContactTransferData, Builder> {
public Builder() {}
@@ -350,7 +350,7 @@ public class ContactResource extends EppResource
}
@Override
public Builder setTransferData(TransferData transferData) {
public Builder setTransferData(ContactTransferData transferData) {
getInstance().transferData = transferData;
return this;
}
@@ -380,7 +380,7 @@ public class ContactResource extends EppResource
public ContactResource build() {
ContactResource instance = getInstance();
// If TransferData is totally empty, set it to null.
if (TransferData.EMPTY.equals(instance.transferData)) {
if (ContactTransferData.EMPTY.equals(instance.transferData)) {
setTransferData(null);
}
// Set the searchName using the internationalized and localized postal info names.

View File

@@ -63,7 +63,7 @@ import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.HostResource;
import google.registry.model.poll.PollMessage;
import google.registry.model.registry.Registry;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferStatus;
import google.registry.persistence.VKey;
import google.registry.persistence.WithStringVKey;
@@ -110,7 +110,9 @@ import org.joda.time.Interval;
@WithStringVKey
@ExternalMessagingName("domain")
public class DomainBase extends EppResource
implements DatastoreAndSqlEntity, ForeignKeyedEppResource, ResourceWithTransferData {
implements DatastoreAndSqlEntity,
ForeignKeyedEppResource,
ResourceWithTransferData<DomainTransferData> {
/** The max number of years that a domain can be registered for, as set by ICANN policy. */
public static final int MAX_REGISTRATION_YEARS = 10;
@@ -253,7 +255,7 @@ public class DomainBase extends EppResource
String smdId;
/** Data about any pending or past transfers on this domain. */
TransferData transferData;
DomainTransferData transferData;
/**
* The time that this resource was last transferred.
@@ -322,8 +324,8 @@ public class DomainBase extends EppResource
}
@Override
public TransferData getTransferData() {
return Optional.ofNullable(transferData).orElse(TransferData.EMPTY);
public DomainTransferData getTransferData() {
return Optional.ofNullable(transferData).orElse(DomainTransferData.EMPTY);
}
@Override
@@ -402,7 +404,7 @@ public class DomainBase extends EppResource
@Override
public DomainBase cloneProjectedAtTime(final DateTime now) {
TransferData transferData = getTransferData();
DomainTransferData transferData = getTransferData();
DateTime transferExpirationTime = transferData.getPendingTransferExpirationTime();
// If there's a pending transfer that has expired, handle it.
@@ -644,7 +646,7 @@ public class DomainBase extends EppResource
/** A builder for constructing {@link DomainBase}, since it is immutable. */
public static class Builder extends EppResource.Builder<DomainBase, Builder>
implements BuilderWithTransferData<Builder> {
implements BuilderWithTransferData<DomainTransferData, Builder> {
public Builder() {}
@@ -656,7 +658,7 @@ public class DomainBase extends EppResource
public DomainBase build() {
DomainBase instance = getInstance();
// If TransferData is totally empty, set it to null.
if (TransferData.EMPTY.equals(getInstance().transferData)) {
if (DomainTransferData.EMPTY.equals(getInstance().transferData)) {
setTransferData(null);
}
// A DomainBase has status INACTIVE if there are no nameservers.
@@ -830,7 +832,7 @@ public class DomainBase extends EppResource
}
@Override
public Builder setTransferData(TransferData transferData) {
public Builder setTransferData(DomainTransferData transferData) {
getInstance().transferData = transferData;
return thisCastToDerived();
}

View File

@@ -121,5 +121,10 @@ public abstract class BaseTransferObject extends ImmutableObject {
getInstance().pendingTransferExpirationTime = pendingTransferExpirationTime;
return thisCastToDerived();
}
@Override
public T build() {
return super.build();
}
}
}

View File

@@ -0,0 +1,48 @@
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.model.transfer;
import com.googlecode.objectify.annotation.Embed;
import com.googlecode.objectify.annotation.Unindex;
import javax.persistence.Embeddable;
/** Transfer data for contact. */
@Embed
@Unindex
@Embeddable
public class ContactTransferData extends TransferData<ContactTransferData.Builder> {
public static final ContactTransferData EMPTY = new ContactTransferData();
@Override
public boolean isEmpty() {
return EMPTY.equals(this);
}
@Override
public Builder asBuilder() {
return new Builder(clone(this));
}
public static class Builder
extends TransferData.Builder<ContactTransferData, ContactTransferData.Builder> {
/** Create a {@link ContactTransferData.Builder} wrapping a new instance. */
public Builder() {}
/** Create a {@link ContactTransferData.Builder} wrapping the given instance. */
private Builder(ContactTransferData instance) {
super(instance);
}
}
}

View File

@@ -0,0 +1,186 @@
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.model.transfer;
import com.googlecode.objectify.annotation.Embed;
import com.googlecode.objectify.annotation.Ignore;
import com.googlecode.objectify.annotation.IgnoreSave;
import com.googlecode.objectify.annotation.Unindex;
import com.googlecode.objectify.condition.IfNull;
import google.registry.model.billing.BillingEvent;
import google.registry.model.domain.Period;
import google.registry.model.domain.Period.Unit;
import google.registry.model.poll.PollMessage;
import google.registry.persistence.VKey;
import javax.annotation.Nullable;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import org.joda.time.DateTime;
/** Transfer data for domain. */
@Embed
@Unindex
@Embeddable
public class DomainTransferData extends TransferData<DomainTransferData.Builder> {
public static final DomainTransferData EMPTY = new DomainTransferData();
/**
* The period to extend the registration upon completion of the transfer.
*
* <p>By default, domain transfers are for one year. This can be changed to zero by using the
* superuser EPP extension.
*/
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "unit", column = @Column(name = "transfer_renew_period_unit")),
@AttributeOverride(name = "value", column = @Column(name = "transfer_renew_period_value"))
})
Period transferPeriod = Period.create(1, Unit.YEARS);
/**
* The registration expiration time resulting from the approval - speculative or actual - of the
* most recent transfer request, applicable for domains only.
*
* <p>For pending transfers, this is the expiration time that will take effect under a projected
* server approval. For approved transfers, this is the actual expiration time of the domain as of
* the moment of transfer completion. For rejected or cancelled transfers, this field will be
* reset to null.
*
* <p>Note that even when this field is set, it does not necessarily mean that the post-transfer
* domain has a new expiration time. Superuser transfers may not include a bundled 1 year renewal
* at all, or even when a renewal is bundled, for a transfer during the autorenew grace period the
* bundled renewal simply subsumes the recent autorenewal, resulting in the same expiration time.
*/
// TODO(b/36405140): backfill this field for existing domains to which it should apply.
@Column(name = "transfer_registration_expiration_time")
DateTime transferredRegistrationExpirationTime;
@Ignore
@Column(name = "transfer_billing_cancellation_id")
Long billingCancellationId;
/**
* The regular one-time billing event that will be charged for 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.
*
* <p>TODO(b/158230654) Remove unused columns for TransferData in Contact table.
*/
@IgnoreSave(IfNull.class)
@Column(name = "transfer_billing_event_id")
VKey<BillingEvent.OneTime> serverApproveBillingEvent;
/**
* The autorenew billing event that should be associated with this resource after the 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.
*/
@IgnoreSave(IfNull.class)
@Column(name = "transfer_billing_recurrence_id")
VKey<BillingEvent.Recurring> serverApproveAutorenewEvent;
/**
* The autorenew poll message that should be associated with this resource after the 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.
*/
@IgnoreSave(IfNull.class)
@Column(name = "transfer_autorenew_poll_message_id")
VKey<PollMessage.Autorenew> serverApproveAutorenewPollMessage;
@Override
public Builder copyConstantFieldsToBuilder() {
return super.copyConstantFieldsToBuilder().setTransferPeriod(this.transferPeriod);
}
public Period getTransferPeriod() {
return transferPeriod;
}
@Nullable
public DateTime getTransferredRegistrationExpirationTime() {
return transferredRegistrationExpirationTime;
}
@Nullable
public VKey<BillingEvent.OneTime> getServerApproveBillingEvent() {
return serverApproveBillingEvent;
}
@Nullable
public VKey<BillingEvent.Recurring> getServerApproveAutorenewEvent() {
return serverApproveAutorenewEvent;
}
@Nullable
public VKey<PollMessage.Autorenew> getServerApproveAutorenewPollMessage() {
return serverApproveAutorenewPollMessage;
}
@Override
public boolean isEmpty() {
return EMPTY.equals(this);
}
@Override
public Builder asBuilder() {
return new Builder(clone(this));
}
public static class Builder extends TransferData.Builder<DomainTransferData, Builder> {
/** Create a {@link DomainTransferData.Builder} wrapping a new instance. */
public Builder() {}
/** Create a {@link Builder} wrapping the given instance. */
private Builder(DomainTransferData instance) {
super(instance);
}
public Builder setTransferPeriod(Period transferPeriod) {
getInstance().transferPeriod = transferPeriod;
return this;
}
public Builder setTransferredRegistrationExpirationTime(
DateTime transferredRegistrationExpirationTime) {
getInstance().transferredRegistrationExpirationTime = transferredRegistrationExpirationTime;
return this;
}
public Builder setServerApproveBillingEvent(
VKey<BillingEvent.OneTime> serverApproveBillingEvent) {
getInstance().serverApproveBillingEvent = serverApproveBillingEvent;
return this;
}
public Builder setServerApproveAutorenewEvent(
VKey<BillingEvent.Recurring> serverApproveAutorenewEvent) {
getInstance().serverApproveAutorenewEvent = serverApproveAutorenewEvent;
return this;
}
public Builder setServerApproveAutorenewPollMessage(
VKey<PollMessage.Autorenew> serverApproveAutorenewPollMessage) {
getInstance().serverApproveAutorenewPollMessage = serverApproveAutorenewPollMessage;
return this;
}
}
}

View File

@@ -17,38 +17,31 @@ package google.registry.model.transfer;
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.annotation.Embed;
import com.googlecode.objectify.annotation.Ignore;
import com.googlecode.objectify.annotation.IgnoreSave;
import com.googlecode.objectify.annotation.Unindex;
import com.googlecode.objectify.condition.IfNull;
import google.registry.model.Buildable;
import google.registry.model.EppResource;
import google.registry.model.billing.BillingEvent;
import google.registry.model.domain.Period;
import google.registry.model.domain.Period.Unit;
import google.registry.model.eppcommon.Trid;
import google.registry.model.poll.PollMessage;
import google.registry.persistence.VKey;
import google.registry.util.TypeUtils.TypeInstantiator;
import java.util.Set;
import javax.annotation.Nullable;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import org.joda.time.DateTime;
/**
* Common transfer data for {@link EppResource} types. Only applies to domains and contacts; hosts
* are implicitly transferred with their superordinate domain.
*/
@Embed
@Unindex
@javax.persistence.Embeddable
public class TransferData extends BaseTransferObject implements Buildable {
public static final TransferData EMPTY = new TransferData();
@MappedSuperclass
public abstract class TransferData<
B extends TransferData.Builder<? extends TransferData, ? extends TransferData.Builder>>
extends BaseTransferObject implements Buildable {
/** The transaction id of the most recent transfer request (or null if there never was one). */
@Embedded
@@ -62,37 +55,6 @@ public class TransferData extends BaseTransferObject implements Buildable {
})
Trid transferRequestTrid;
/**
* The period to extend the registration upon completion of the transfer.
*
* <p>By default, domain transfers are for one year. This can be changed to zero by using the
* superuser EPP extension.
*/
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "unit", column = @Column(name = "transfer_renew_period_unit")),
@AttributeOverride(name = "value", column = @Column(name = "transfer_renew_period_value"))
})
Period transferPeriod = Period.create(1, Unit.YEARS);
/**
* The registration expiration time resulting from the approval - speculative or actual - of the
* most recent transfer request, applicable for domains only.
*
* <p>For pending transfers, this is the expiration time that will take effect under a projected
* server approval. For approved transfers, this is the actual expiration time of the domain as of
* the moment of transfer completion. For rejected or cancelled transfers, this field will be
* reset to null.
*
* <p>Note that even when this field is set, it does not necessarily mean that the post-transfer
* domain has a new expiration time. Superuser transfers may not include a bundled 1 year renewal
* at all, or even when a renewal is bundled, for a transfer during the autorenew grace period the
* bundled renewal simply subsumes the recent autorenewal, resulting in the same expiration time.
*/
// TODO(b/36405140): backfill this field for existing domains to which it should apply.
@Column(name = "transfer_registration_expiration_time")
DateTime transferredRegistrationExpirationTime;
/**
* The billing event and poll messages associated with a server-approved transfer.
*
@@ -116,85 +78,26 @@ public class TransferData extends BaseTransferObject implements Buildable {
@Column(name = "transfer_losing_poll_message_id")
Long losingTransferPollMessageId;
@Ignore
@Column(name = "transfer_billing_cancellation_id")
Long billingCancellationId;
/**
* The regular one-time billing event that will be charged for 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.
*
* <p>TODO(b/158230654) Remove unused columns for TransferData in Contact table.
*/
@IgnoreSave(IfNull.class)
@Column(name = "transfer_billing_event_id")
VKey<BillingEvent.OneTime> serverApproveBillingEvent;
/**
* The autorenew billing event that should be associated with this resource after the 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.
*/
@IgnoreSave(IfNull.class)
@Column(name = "transfer_billing_recurrence_id")
VKey<BillingEvent.Recurring> serverApproveAutorenewEvent;
/**
* The autorenew poll message that should be associated with this resource after the 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.
*/
@IgnoreSave(IfNull.class)
@Column(name = "transfer_autorenew_poll_message_id")
VKey<PollMessage.Autorenew> serverApproveAutorenewPollMessage;
public abstract boolean isEmpty();
@Nullable
public Trid getTransferRequestTrid() {
return transferRequestTrid;
}
public Period getTransferPeriod() {
return transferPeriod;
}
@Nullable
public DateTime getTransferredRegistrationExpirationTime() {
return transferredRegistrationExpirationTime;
}
public ImmutableSet<VKey<? extends TransferServerApproveEntity>> getServerApproveEntities() {
return nullToEmptyImmutableCopy(serverApproveEntities);
}
@Nullable
public VKey<BillingEvent.OneTime> getServerApproveBillingEvent() {
return serverApproveBillingEvent;
}
@Nullable
public VKey<BillingEvent.Recurring> getServerApproveAutorenewEvent() {
return serverApproveAutorenewEvent;
}
@Nullable
public VKey<PollMessage.Autorenew> getServerApproveAutorenewPollMessage() {
return serverApproveAutorenewPollMessage;
}
@Override
public Builder asBuilder() {
return new Builder(clone(this));
}
public abstract Builder asBuilder();
/**
* Returns a fresh Builder populated only with the constant fields of this TransferData, i.e.
* those that are fixed and unchanging throughout the transfer process.
*
* <p>These fields are:
*
* <ul>
* <li>transferRequestTrid
* <li>transferRequestTime
@@ -203,64 +106,43 @@ public class TransferData extends BaseTransferObject implements Buildable {
* <li>transferPeriod
* </ul>
*/
public Builder copyConstantFieldsToBuilder() {
return new Builder()
public B copyConstantFieldsToBuilder() {
B newBuilder = new TypeInstantiator<B>(getClass()) {}.instantiate();
newBuilder
// .setTransferPeriod(this.transferPeriod)
.setTransferRequestTrid(this.transferRequestTrid)
.setTransferRequestTime(this.transferRequestTime)
.setGainingClientId(this.gainingClientId)
.setLosingClientId(this.losingClientId)
.setTransferPeriod(this.transferPeriod);
.setLosingClientId(this.losingClientId);
return newBuilder;
}
/** Builder for {@link TransferData} because it is immutable. */
public static class Builder extends BaseTransferObject.Builder<TransferData, Builder> {
public abstract static class Builder<T extends TransferData, B extends Builder<T, B>>
extends BaseTransferObject.Builder<T, B> {
/** Create a {@link Builder} wrapping a new instance. */
public Builder() {}
/** Create a {@link Builder} wrapping the given instance. */
private Builder(TransferData instance) {
protected Builder(T instance) {
super(instance);
}
public Builder setTransferRequestTrid(Trid transferRequestTrid) {
public B setTransferRequestTrid(Trid transferRequestTrid) {
getInstance().transferRequestTrid = transferRequestTrid;
return this;
return thisCastToDerived();
}
public Builder setTransferPeriod(Period transferPeriod) {
getInstance().transferPeriod = transferPeriod;
return this;
}
public Builder setTransferredRegistrationExpirationTime(
DateTime transferredRegistrationExpirationTime) {
getInstance().transferredRegistrationExpirationTime = transferredRegistrationExpirationTime;
return this;
}
public Builder setServerApproveEntities(
public B setServerApproveEntities(
ImmutableSet<VKey<? extends TransferServerApproveEntity>> serverApproveEntities) {
getInstance().serverApproveEntities = serverApproveEntities;
return this;
return thisCastToDerived();
}
public Builder setServerApproveBillingEvent(
VKey<BillingEvent.OneTime> serverApproveBillingEvent) {
getInstance().serverApproveBillingEvent = serverApproveBillingEvent;
return this;
}
public Builder setServerApproveAutorenewEvent(
VKey<BillingEvent.Recurring> serverApproveAutorenewEvent) {
getInstance().serverApproveAutorenewEvent = serverApproveAutorenewEvent;
return this;
}
public Builder setServerApproveAutorenewPollMessage(
VKey<PollMessage.Autorenew> serverApproveAutorenewPollMessage) {
getInstance().serverApproveAutorenewPollMessage = serverApproveAutorenewPollMessage;
return this;
@Override
public T build() {
return super.build();
}
}

View File

@@ -36,7 +36,6 @@ import google.registry.xjc.eppcom.XjcEppcomTrStatusType;
import google.registry.xjc.rdecontact.XjcRdeContact;
import google.registry.xjc.rdecontact.XjcRdeContactElement;
import google.registry.xjc.rdecontact.XjcRdeContactTransferDataType;
import java.util.Objects;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
@@ -102,7 +101,7 @@ final class ContactResourceToXjcConverter {
// required before an automated response action will be taken by
// the registry. For all other status types, the value identifies
// the date and time when the request was completed.
if (!Objects.equals(model.getTransferData(), TransferData.EMPTY)) {
if (!model.getTransferData().isEmpty()) {
bean.setTrnData(convertTransferData(model.getTransferData()));
}

View File

@@ -28,6 +28,7 @@ import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.rde.RdeMode;
import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferData;
import google.registry.persistence.VKey;
import google.registry.util.Idn;
@@ -234,7 +235,7 @@ final class DomainBaseToXjcConverter {
// * An OPTIONAL <exDate> element that contains the end of the
// domain name object's validity period (expiry date) if the
// transfer caused or causes a change in the validity period.
if (!model.getTransferData().equals(TransferData.EMPTY)) {
if (!model.getTransferData().isEmpty()) {
// Temporary check to make sure that there really was a transfer. A bug caused spurious
// empty transfer records to get generated for deleted domains.
// TODO(b/33289763): remove the hasGainingAndLosingRegistrars check in February 2017
@@ -258,7 +259,7 @@ final class DomainBaseToXjcConverter {
}
/** Converts {@link TransferData} to {@link XjcRdeDomainTransferDataType}. */
private static XjcRdeDomainTransferDataType convertTransferData(TransferData model) {
private static XjcRdeDomainTransferDataType convertTransferData(DomainTransferData model) {
XjcRdeDomainTransferDataType bean = new XjcRdeDomainTransferDataType();
bean.setTrStatus(
XjcEppcomTrStatusType.fromValue(model.getTransferStatus().getXmlName()));