diff --git a/java/google/registry/model/domain/DomainApplication.java b/java/google/registry/model/domain/DomainApplication.java
index 5bb948043..88c0430d2 100644
--- a/java/google/registry/model/domain/DomainApplication.java
+++ b/java/google/registry/model/domain/DomainApplication.java
@@ -14,17 +14,24 @@
package google.registry.model.domain;
+import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.model.ofy.Ofy.RECOMMENDED_MEMCACHE_EXPIRATION;
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
import com.google.common.collect.ImmutableList;
import com.googlecode.objectify.annotation.Cache;
import com.googlecode.objectify.annotation.EntitySubclass;
+import com.googlecode.objectify.annotation.OnLoad;
import google.registry.model.annotations.ExternalMessagingName;
import google.registry.model.domain.launch.ApplicationStatus;
import google.registry.model.domain.launch.LaunchPhase;
import google.registry.model.eppcommon.Trid;
+import google.registry.model.eppinput.EppInput;
+import google.registry.model.eppinput.EppInput.ResourceCommandWrapper;
+import google.registry.model.reporting.HistoryEntry;
import google.registry.model.smd.EncodedSignedMark;
+import google.registry.xml.XmlTransformer;
+import java.io.ByteArrayInputStream;
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
@@ -72,7 +79,7 @@ public class DomainApplication extends DomainBase {
/** The requested registration period. */
@XmlTransient
Period period;
-
+
/** The current status of this application. */
@XmlTransient
ApplicationStatus applicationStatus;
@@ -85,6 +92,70 @@ public class DomainApplication extends DomainBase {
@XmlTransient
Money auctionPrice;
+ // TODO(b/32447342): remove this once the period has been populated on all DomainApplications
+ @OnLoad
+ void setYears() {
+ if (period == null) {
+ // Extract the registration period from the XML used to create the domain application.
+ try {
+ HistoryEntry history = ofy().load()
+ .type(HistoryEntry.class)
+ .ancestor(this)
+ .order("modificationTime")
+ .first()
+ .now();
+ if (history != null) {
+ byte[] xmlBytes = history.getXmlBytes();
+ EppInput eppInput = unmarshal(EppInput.class, xmlBytes);
+ period = ((DomainCommand.Create)
+ ((ResourceCommandWrapper) eppInput.getCommandWrapper().getCommand())
+ .getResourceCommand()).getPeriod();
+ }
+ } catch (Exception e) {
+ // If we encounter an exception, give up on this defaulting.
+ }
+ }
+ }
+
+ /**
+ * Unmarshal bytes into Epp classes.
+ *
+ *
This method, and the things it depends on, are copied from EppXmlTransformer, because that
+ * class is in the flows directory, and we don't want a build dependency of model on build. It can
+ * be removed when the @OnLoad method is removed.
+ *
+ * @param clazz type to return, specified as a param to enforce typesafe generics
+ * @see "http://errorprone.info/bugpattern/TypeParameterUnusedInFormals"
+ */
+ private static T unmarshal(Class clazz, byte[] bytes) throws Exception {
+ return INPUT_TRANSFORMER.unmarshal(clazz, new ByteArrayInputStream(bytes));
+ }
+
+ // Hardcoded XML schemas, ordered with respect to dependency.
+ private static final ImmutableList SCHEMAS = ImmutableList.of(
+ "eppcom.xsd",
+ "epp.xsd",
+ "contact.xsd",
+ "host.xsd",
+ "domain.xsd",
+ "rgp.xsd",
+ "secdns.xsd",
+ "fee06.xsd",
+ "fee11.xsd",
+ "fee12.xsd",
+ "metadata.xsd",
+ "mark.xsd",
+ "dsig.xsd",
+ "smd.xsd",
+ "launch.xsd",
+ "allocate.xsd",
+ "flags.xsd");
+
+ private static final XmlTransformer INPUT_TRANSFORMER =
+ new XmlTransformer(SCHEMAS, EppInput.class);
+
+ // End of copied stuff used by @OnLoad method
+
@Override
public String getFullyQualifiedDomainName() {
return fullyQualifiedDomainName;
@@ -158,7 +229,7 @@ public class DomainApplication extends DomainBase {
getInstance().phase = phase;
return this;
}
-
+
public Builder setPeriod(Period period) {
getInstance().period = period;
return this;
diff --git a/javatests/google/registry/model/domain/DomainApplicationTest.java b/javatests/google/registry/model/domain/DomainApplicationTest.java
index 4c62c98d8..364ee21f7 100644
--- a/javatests/google/registry/model/domain/DomainApplicationTest.java
+++ b/javatests/google/registry/model/domain/DomainApplicationTest.java
@@ -16,6 +16,7 @@ package google.registry.model.domain;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.EppResourceUtils.loadDomainApplication;
+import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.testing.DatastoreHelper.cloneAndSetAutoTimestamps;
import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.DatastoreHelper.newDomainApplication;
@@ -23,12 +24,17 @@ import static google.registry.testing.DatastoreHelper.newHostResource;
import static google.registry.testing.DatastoreHelper.persistActiveContact;
import static google.registry.testing.DatastoreHelper.persistActiveHost;
import static google.registry.testing.DatastoreHelper.persistResource;
+import static google.registry.testing.FullFieldsTestEntityHelper.makeHistoryEntry;
+import static google.registry.testing.TestDataHelper.loadFileWithSubstitutions;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.joda.money.CurrencyUnit.USD;
+import static org.joda.time.DateTimeZone.UTC;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
+import com.googlecode.objectify.VoidWork;
import google.registry.model.EntityTestCase;
import google.registry.model.billing.BillingEvent;
import google.registry.model.domain.launch.ApplicationStatus;
@@ -39,12 +45,14 @@ import google.registry.model.eppcommon.AuthInfo.PasswordAuth;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppcommon.Trid;
import google.registry.model.host.HostResource;
+import google.registry.model.reporting.HistoryEntry;
import google.registry.model.smd.EncodedSignedMark;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferData.TransferServerApproveEntity;
import google.registry.model.transfer.TransferStatus;
import google.registry.testing.ExceptionRule;
import org.joda.money.Money;
+import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -102,7 +110,7 @@ public class DomainApplicationTest extends EntityTestCase {
.build())
.setCreationTrid(Trid.create("client creation trid"))
.setPhase(LaunchPhase.LANDRUSH)
- .setPeriod(Period.create(5, Period.Unit.YEARS))
+ // TODO(b/32447342): set period
.setEncodedSignedMarks(ImmutableList.of(EncodedSignedMark.create("base64", "abcdefg=")))
.setApplicationStatus(ApplicationStatus.ALLOCATED)
.setAuctionPrice(Money.of(USD, 11))
@@ -118,6 +126,8 @@ public class DomainApplicationTest extends EntityTestCase {
@Test
public void testIndexing() throws Exception {
+ domainApplication = persistResource(
+ domainApplication.asBuilder().setPeriod(Period.create(5, Period.Unit.YEARS)).build());
verifyIndexing(
domainApplication,
"allContacts.contactId.linked",
@@ -188,4 +198,71 @@ public class DomainApplicationTest extends EntityTestCase {
// If there are circular references, this will overflow the stack.
domainApplication.toHydratedString();
}
+
+ // TODO(b/32447342): remove this once the period has been populated on all DomainApplications
+ private void triggerTheOnLoadMethod() {
+ ofy().transact(new VoidWork() {
+ @Override
+ public void vrun() {
+ domainApplication = ofy().load().fromEntity(ofy().save().toEntity(domainApplication));
+ }
+ });
+ }
+
+ // TODO(b/32447342): remove this once the period has been populated on all DomainApplications
+ @Test
+ public void testPeriodIsNullByDefault() {
+ triggerTheOnLoadMethod();
+ assertThat(domainApplication.getPeriod()).isNull();
+ }
+
+ // TODO(b/32447342): remove this once the period has been populated on all DomainApplications
+ @Test
+ public void testPeriodIsOneYearBecauseHistoryEntryHasNoPeriod() {
+ persistResource(makeHistoryEntry(
+ domainApplication,
+ HistoryEntry.Type.DOMAIN_APPLICATION_CREATE,
+ Period.create(5, Period.Unit.YEARS),
+ "testing",
+ DateTime.now(UTC),
+ loadFileWithSubstitutions(
+ getClass(), "domain_create_landrush.xml", ImmutableMap.of())));
+ triggerTheOnLoadMethod();
+ assertThat(domainApplication.getPeriod()).isNotNull();
+ assertThat(domainApplication.getPeriod()).isEqualTo(Period.create(1, Period.Unit.YEARS));
+ }
+
+ // TODO(b/32447342): remove this once the period has been populated on all DomainApplications
+ @Test
+ public void testPeriodDefaultedFromHistoryEntry() {
+ persistResource(makeHistoryEntry(
+ domainApplication,
+ HistoryEntry.Type.DOMAIN_APPLICATION_CREATE,
+ Period.create(5, Period.Unit.YEARS),
+ "testing",
+ DateTime.now(UTC),
+ loadFileWithSubstitutions(
+ getClass(), "domain_create_landrush_with_period.xml", ImmutableMap.of("PERIOD", "5"))));
+ triggerTheOnLoadMethod();
+ assertThat(domainApplication.getPeriod()).isNotNull();
+ assertThat(domainApplication.getPeriod()).isEqualTo(Period.create(5, Period.Unit.YEARS));
+ }
+
+ // TODO(b/32447342): remove this once the period has been populated on all DomainApplications
+ @Test
+ public void testPeriodAlreadySet() {
+ domainApplication = persistResource(
+ domainApplication.asBuilder().setPeriod(Period.create(1, Period.Unit.YEARS)).build());
+ persistResource(makeHistoryEntry(
+ domainApplication,
+ HistoryEntry.Type.DOMAIN_APPLICATION_CREATE,
+ Period.create(5, Period.Unit.YEARS),
+ "testing",
+ DateTime.now(UTC),
+ loadFileWithSubstitutions(
+ getClass(), "domain_create_landrush_with_period.xml", ImmutableMap.of("PERIOD", "5"))));
+ triggerTheOnLoadMethod();
+ assertThat(domainApplication.getPeriod()).isNotNull();
+ assertThat(domainApplication.getPeriod()).isEqualTo(Period.create(1, Period.Unit.YEARS));
+ }
}
diff --git a/javatests/google/registry/model/domain/testdata/domain_create_landrush_with_period.xml b/javatests/google/registry/model/domain/testdata/domain_create_landrush_with_period.xml
new file mode 100644
index 000000000..47a2c9f3c
--- /dev/null
+++ b/javatests/google/registry/model/domain/testdata/domain_create_landrush_with_period.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+ example.tld
+ %PERIOD%
+ jd1234
+ sh8013
+ sh8013
+
+ 2fooBAR
+
+
+
+
+
+ landrush
+
+
+ ABC-12345
+
+
diff --git a/javatests/google/registry/testing/FullFieldsTestEntityHelper.java b/javatests/google/registry/testing/FullFieldsTestEntityHelper.java
index 4a0c6f44e..46fcb2af8 100644
--- a/javatests/google/registry/testing/FullFieldsTestEntityHelper.java
+++ b/javatests/google/registry/testing/FullFieldsTestEntityHelper.java
@@ -266,11 +266,21 @@ public final class FullFieldsTestEntityHelper {
Period period,
String reason,
DateTime modificationTime) {
+ return makeHistoryEntry(resource, type, period, reason, modificationTime, "");
+ }
+
+ public static HistoryEntry makeHistoryEntry(
+ EppResource resource,
+ HistoryEntry.Type type,
+ Period period,
+ String reason,
+ DateTime modificationTime,
+ String xml) {
HistoryEntry.Builder builder = new HistoryEntry.Builder()
.setParent(resource)
.setType(type)
.setPeriod(period)
- .setXmlBytes("".getBytes(UTF_8))
+ .setXmlBytes(xml.getBytes(UTF_8))
.setModificationTime(modificationTime)
.setClientId("foo")
.setTrid(Trid.create("ABC-123"))