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

Compare commits

...

9 Commits

Author SHA1 Message Date
Ben McIlwain f6d2a7ff91 Rename DomainContent -> DomainBase (#1729)
* Rename DomainContent -> DomainBase

This is a follow-up to PR #1725 which renamed DomainBase to Domain. Now, the
class naming hierarchy has the same structure as ContactBase/HostBase.
2022-08-02 17:21:17 -04:00
Pavlo Tkach 35530616d6 Add docker prerequisite to install guide (#1728) 2022-08-02 16:20:59 -04:00
Ben McIlwain ede919d7dc Rename DomainBase -> Domain (#1725)
* Rename DomainBase -> Domain

This was a long time coming, but we couldn't do it until we left Datastore, as
the Java class name has to match the Datastore entity name.

Subsequent PRs will rename ContactResource to Contact and HostResource to Host,
so that everything matches the SQL table names (and is shorter!).

* Merge branch 'master' into rename-domainbase
2022-08-02 16:03:30 -04:00
Lai Jiang 827b7db227 Make Kythe run work with Gradle 7 (#1727)
The fix is based on b/240627423. I tested locally and was able to build
with the -PenableCrossReferencing=true flag successfully.

TESTED=run the kythe GCB pipeline locally.
2022-08-02 13:19:47 -04:00
Lai Jiang 1aefd9a78d Remove ofy support from BillingEvent (#1710)
This PR turns out to be more massive than I would have liked but it
  deals with all billing event related stuff, which are more or link all
  intertwined:

  * Remove all billing events as Ofy entities.
  * Add a temporary annotation to allow BillingEvent's ID to be
    auto-allocated by ofy while not lacking the Ofy @Id annotation.
  * Remove Modification, which is only used in ofy.
  * Remove BillingVKey, as we do not need to store the ofy key parent
     information anymore. The VKey for a billing event now just contain
     its primary key, and can be converted by VKeyConverter.
  * Remove BigQuery related code in the billing pipeline.

  Note that after BillingVKey is removed, several columns in
  BillingCancellation are no longer needed. The change to database schema
  will be handled in https://github.com/google/nomulus/pull/1721 after
  this PR is deployed to production.

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/google/nomulus/1710)
<!-- Reviewable:end -->
2022-08-02 11:36:28 -04:00
Ben McIlwain 950d12577f Revert "Upgrade App Engine Standard to Java 17 w/ bundled APIs (#1714)" (#1724)
* Revert "Upgrade App Engine Standard to Java 17 w/ bundled APIs (#1714)"

This partially reverts commit d8e77e2ab2 (it keeps
intact unrelated version upgrades).

We need to temporarily revert this because Spinnaker isn't quite yet playing
nice with the new <app-engine-apis> configuration option in appengine-web.xml
(it seems like this was added recently and Spinnaker is still stuck on App
Engine SDK version 1.9.82 which predates it). Hopefully we can get that
dependency updated in Spinnaker soon and then we can re-upgrade to Java 17.
2022-07-29 16:08:36 -04:00
sarahcaseybot 5d559085d7 Flyway files for adding current_package_token column to Domain table (#1719)
* Flyway files for adding allocationToken column to Domain table

* Rename column to current_package_token

* Update er diagram

* Add foreign key to DomainHistory
2022-07-29 12:35:43 -04:00
Ben McIlwain 268c1048cc Delete the BackfillRegistrarBillingAccounts scrap command (#1722) 2022-07-29 11:40:11 -04:00
Ben McIlwain 74e22089fe Remove the withoutBackup methods from TransactionManager (#1723)
* Remove the withoutBackup methods from TransactionManager

This doesn't do anything in Cloud SQL (it was for Ofy only).
2022-07-29 11:39:56 -04:00
301 changed files with 8216 additions and 9922 deletions
+2 -2
View File
@@ -207,8 +207,8 @@ allprojects {
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.fork = true
options.forkOptions.executable =
"${project.rootDir}/kythe/extractors/javac-wrapper.sh"
options.forkOptions.javaHome =
file("${System.env.REAL_JAVA_HOME}")
}
}
}
+6 -7
View File
@@ -31,10 +31,10 @@ com.github.jnr:jnr-unixsocket:0.38.17=compileClasspath,default,deploy_jar,nonpro
com.github.jnr:jnr-x86asm:1.0.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.kevinstern:software-and-algorithms:1.0=annotationProcessor,errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
com.google.android:annotations:4.1.1.4=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
com.google.api-client:google-api-client-appengine:1.32.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api-client:google-api-client-appengine:1.35.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api-client:google-api-client-jackson2:1.32.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api-client:google-api-client-java6:1.35.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api-client:google-api-client-servlet:1.32.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api-client:google-api-client-servlet:1.35.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api-client:google-api-client:1.35.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1:2.12.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.136.2=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
@@ -90,13 +90,12 @@ com.google.apis:google-api-services-pubsub:v1-rev20211130-1.32.1=compileClasspat
com.google.apis:google-api-services-sheets:v4-rev20220620-1.32.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-sqladmin:v1beta4-rev20220623-1.32.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-storage:v1-rev20220705-1.32.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.appengine.tools:appengine-gcs-client:0.8.3=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.appengine.tools:appengine-gcs-client:0.8.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.appengine.tools:appengine-pipeline:0.2.13=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.appengine:appengine-api-1.0-sdk:2.0.5=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.appengine:appengine-api-stubs:2.0.5=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.appengine:appengine-api-stubs:2.0.5=testCompileClasspath,testRuntimeClasspath
com.google.appengine:appengine-remote-api:2.0.5=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.appengine:appengine-testing:2.0.5=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.appengine:appengine-tools-sdk:2.0.5=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.appengine:appengine-testing:1.9.86=default,deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auth:google-auth-library-credentials:1.8.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auth:google-auth-library-oauth2-http:1.8.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auto.service:auto-service-annotations:1.0.1=annotationProcessor,compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
@@ -300,7 +299,7 @@ javax.validation:validation-api:1.0.0.GA=compileClasspath,default,deploy_jar,non
javax.xml.bind:jaxb-api:2.3.1=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
javax.xml.bind:jaxb-api:2.4.0-b180830.0359=jaxb
jline:jline:1.0=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
joda-time:joda-time:2.10.13=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
joda-time:joda-time:2.10.10=compileClasspath,default,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
junit:junit:4.13.2=default,nonprodCompileClasspath,nonprodRuntimeClasspath,testCompileClasspath,testRuntimeClasspath
net.arnx:nashorn-promise:0.1.1=nonprodRuntime,runtime,testRuntimeClasspath
net.bytebuddy:byte-buddy-agent:1.12.10=testCompileClasspath,testRuntimeClasspath
@@ -32,7 +32,7 @@ import google.registry.flows.EppController;
import google.registry.flows.EppRequestSource;
import google.registry.flows.PasswordOnlyTransportCredentials;
import google.registry.flows.StatelessRequestSessionMetadata;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.eppcommon.ProtocolDefinition;
import google.registry.model.eppoutput.EppOutput;
import google.registry.persistence.transaction.QueryComposer.Comparator;
@@ -128,10 +128,10 @@ public class DeleteExpiredDomainsAction implements Runnable {
logger.atInfo().log(
"Deleting non-renewing domains with autorenew end times up through %s.", runTime);
ImmutableList<DomainBase> domainsToDelete =
ImmutableList<Domain> domainsToDelete =
tm().transact(
() ->
tm().createQueryComposer(DomainBase.class)
tm().createQueryComposer(Domain.class)
.where("autorenewEndTime", Comparator.LTE, runTime)
.where("deletionTime", Comparator.EQ, END_OF_TIME)
.list());
@@ -145,10 +145,9 @@ public class DeleteExpiredDomainsAction implements Runnable {
"Found %d domains to delete: %s.",
domainsToDelete.size(),
String.join(
", ",
domainsToDelete.stream().map(DomainBase::getDomainName).collect(toImmutableList())));
", ", domainsToDelete.stream().map(Domain::getDomainName).collect(toImmutableList())));
int successes = 0;
for (DomainBase domain : domainsToDelete) {
for (Domain domain : domainsToDelete) {
if (runDomainDeleteFlow(domain)) {
successes++;
}
@@ -163,7 +162,7 @@ public class DeleteExpiredDomainsAction implements Runnable {
}
/** Runs the actual domain delete flow and returns whether the deletion was successful. */
private boolean runDomainDeleteFlow(DomainBase domain) {
private boolean runDomainDeleteFlow(Domain domain) {
logger.atInfo().log("Attempting to delete domain '%s'.", domain.getDomainName());
// Create a new transaction that the flow's execution will be enlisted in that loads the domain
// transactionally. This way we can ensure that nothing else has modified the domain in question
@@ -171,7 +170,7 @@ public class DeleteExpiredDomainsAction implements Runnable {
Optional<EppOutput> eppOutput =
tm().transact(
() -> {
DomainBase transDomain = tm().loadByKey(domain.createVKey());
Domain transDomain = tm().loadByKey(domain.createVKey());
if (!domain.getAutorenewEndTime().isPresent()
|| domain.getAutorenewEndTime().get().isAfter(tm().getTransactionTime())) {
logger.atSevere().log(
@@ -30,7 +30,7 @@ import google.registry.flows.poll.PollFlowUtils;
import google.registry.model.EppResource;
import google.registry.model.EppResourceUtils;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.host.HostResource;
import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry;
@@ -129,7 +129,7 @@ public class DeleteLoadTestDataAction implements Runnable {
}
VKey<HostResource> hostVKey = host.createVKey();
// We can remove hosts from linked domains, so we should do so then delete the hosts
ImmutableSet<VKey<DomainBase>> linkedDomains =
ImmutableSet<VKey<Domain>> linkedDomains =
EppResourceUtils.getLinkedDomainKeys(hostVKey, clock.nowUtc(), null);
tm().loadByKeys(linkedDomains)
.values()
@@ -37,7 +37,7 @@ import google.registry.config.RegistryEnvironment;
import google.registry.dns.DnsQueue;
import google.registry.model.CreateAutoTimestamp;
import google.registry.model.EppResourceUtils;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.tld.Registry.TldType;
import google.registry.request.Action;
@@ -53,8 +53,8 @@ import org.joda.time.DateTime;
import org.joda.time.Duration;
/**
* Deletes all prober DomainBases and their subordinate history entries, poll messages, and billing
* events, along with their ForeignKeyDomainIndex and EppResourceIndex entities.
* Deletes all prober {@link Domain}s and their subordinate history entries, poll messages, and
* billing events, along with their ForeignKeyDomainIndex and EppResourceIndex entities.
*/
@Action(
service = Action.Service.BACKEND,
@@ -154,7 +154,7 @@ public class DeleteProberDataAction implements Runnable {
// keeping track of which domains to hard-delete (there can be many, so we batch them up)
ScrollableResults scrollableResult =
jpaTm()
.query(DOMAIN_QUERY_STRING, DomainBase.class)
.query(DOMAIN_QUERY_STRING, Domain.class)
.setParameter("tlds", deletableTlds)
.setParameter(
"creationTimeCutoff", CreateAutoTimestamp.create(now.minus(DOMAIN_USED_DURATION)))
@@ -166,7 +166,7 @@ public class DeleteProberDataAction implements Runnable {
ImmutableList.Builder<String> domainRepoIdsToHardDelete = new ImmutableList.Builder<>();
ImmutableList.Builder<String> hostNamesToHardDelete = new ImmutableList.Builder<>();
for (int i = 1; scrollableResult.next(); i = (i + 1) % BATCH_SIZE) {
DomainBase domain = (DomainBase) scrollableResult.get(0);
Domain domain = (Domain) scrollableResult.get(0);
processDomain(
domain,
domainRepoIdsToHardDelete,
@@ -187,7 +187,7 @@ public class DeleteProberDataAction implements Runnable {
}
private void processDomain(
DomainBase domain,
Domain domain,
ImmutableList.Builder<String> domainRepoIdsToHardDelete,
ImmutableList.Builder<String> hostNamesToHardDelete,
AtomicInteger softDeletedDomains,
@@ -251,8 +251,8 @@ public class DeleteProberDataAction implements Runnable {
}
// Take a DNS queue + admin registrar id as input so that it can be called from the mapper as well
private void softDeleteDomain(DomainBase domain) {
DomainBase deletedDomain =
private void softDeleteDomain(Domain domain) {
Domain deletedDomain =
domain.asBuilder().setDeletionTime(tm().getTransactionTime()).setStatusValues(null).build();
DomainHistory historyEntry =
new DomainHistory.Builder()
@@ -266,7 +266,7 @@ public class DeleteProberDataAction implements Runnable {
// Note that we don't bother handling grace periods, billing events, pending transfers, poll
// messages, or auto-renews because those will all be hard-deleted the next time the job runs
// anyway.
tm().putAllWithoutBackup(ImmutableList.of(deletedDomain, historyEntry));
tm().putAll(ImmutableList.of(deletedDomain, historyEntry));
// updating foreign keys is a no-op in SQL
updateForeignKeyIndexDeletionTime(deletedDomain);
dnsQueue.addDomainRefreshTask(deletedDomain.getDomainName());
@@ -43,7 +43,7 @@ import google.registry.model.billing.BillingEvent.Flag;
import google.registry.model.billing.BillingEvent.OneTime;
import google.registry.model.billing.BillingEvent.Recurring;
import google.registry.model.common.Cursor;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.Period;
import google.registry.model.reporting.DomainTransactionRecord;
@@ -253,9 +253,7 @@ public class ExpandRecurringBillingEventsAction implements Runnable {
final ImmutableSet<DateTime> billingTimes =
getBillingTimesInScope(eventTimes, cursorTime, executeTime, tld);
VKey<DomainBase> domainKey =
VKey.create(
DomainBase.class, recurring.getDomainRepoId(), recurring.getParentKey().getParent());
VKey<Domain> domainKey = VKey.createSql(Domain.class, recurring.getDomainRepoId());
Iterable<OneTime> oneTimesForDomain;
oneTimesForDomain =
tm().createQueryComposer(OneTime.class)
@@ -311,11 +309,11 @@ public class ExpandRecurringBillingEventsAction implements Runnable {
.getRenewCost())
.setEventTime(eventTime)
.setFlags(union(recurring.getFlags(), Flag.SYNTHETIC))
.setParent(historyEntry)
.setDomainHistory(historyEntry)
.setPeriodYears(1)
.setReason(recurring.getReason())
.setSyntheticCreationTime(executeTime)
.setCancellationMatchingBillingEvent(recurring.createVKey())
.setCancellationMatchingBillingEvent(recurring)
.setTargetId(recurring.getTargetId())
.build());
}
@@ -27,7 +27,7 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.flogger.FluentLogger;
import com.google.common.net.MediaType;
import google.registry.config.RegistryConfig.Config;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.RegistryLock;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.registrar.Registrar;
@@ -125,7 +125,7 @@ public class RelockDomainAction implements Runnable {
private void relockDomain() {
RegistryLock oldLock = null;
DomainBase domain;
Domain domain;
try {
oldLock =
RegistryLockDao.getByRevisionId(oldUnlockRevisionId)
@@ -134,7 +134,7 @@ public class RelockDomainAction implements Runnable {
new IllegalArgumentException(
String.format("Unknown revision ID %d", oldUnlockRevisionId)));
domain =
tm().loadByKey(VKey.create(DomainBase.class, oldLock.getRepoId()))
tm().loadByKey(VKey.create(Domain.class, oldLock.getRepoId()))
.cloneProjectedAtTime(tm().getTransactionTime());
} catch (Throwable t) {
handleTransientFailure(Optional.ofNullable(oldLock), t);
@@ -180,7 +180,7 @@ public class RelockDomainAction implements Runnable {
}
}
private void verifyDomainAndLockState(RegistryLock oldLock, DomainBase domain) {
private void verifyDomainAndLockState(RegistryLock oldLock, Domain domain) {
// Domain shouldn't be deleted or have a pending transfer/delete
String domainName = domain.getDomainName();
ImmutableSet<StatusValue> statusValues = domain.getStatusValues();
@@ -20,6 +20,7 @@ import dagger.Lazy;
import google.registry.config.CredentialModule;
import google.registry.config.RegistryConfig.Config;
import google.registry.config.RegistryConfig.ConfigModule;
import google.registry.model.domain.Domain;
import google.registry.persistence.PersistenceModule;
import google.registry.persistence.PersistenceModule.BeamBulkQueryJpaTm;
import google.registry.persistence.PersistenceModule.BeamJpaTm;
@@ -53,8 +54,7 @@ public interface RegistryPipelineComponent {
/**
* Returns a {@link JpaTransactionManager} optimized for bulk loading multi-level JPA entities
* ({@link google.registry.model.domain.DomainBase} and {@link
* google.registry.model.domain.DomainHistory}). Please refer to {@link
* ({@link Domain} and {@link google.registry.model.domain.DomainHistory}). Please refer to {@link
* google.registry.model.bulkquery.BulkQueryEntities} for more information.
*/
@BeamBulkQueryJpaTm
@@ -14,47 +14,38 @@
package google.registry.beam.invoicing;
import static google.registry.beam.BeamUtils.checkFieldsNotNull;
import static google.registry.beam.BeamUtils.extractField;
import com.google.auto.value.AutoValue;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import google.registry.model.billing.BillingEvent.Flag;
import google.registry.reporting.billing.BillingModule;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.text.DecimalFormat;
import java.util.stream.Collectors;
import org.apache.avro.generic.GenericRecord;
import java.util.regex.Pattern;
import org.apache.beam.sdk.coders.AtomicCoder;
import org.apache.beam.sdk.coders.Coder;
import org.apache.beam.sdk.coders.StringUtf8Coder;
import org.apache.beam.sdk.io.gcp.bigquery.SchemaAndRecord;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
/**
* A POJO representing a single billable event, parsed from a {@code SchemaAndRecord}.
*
* <p>This is a trivially serializable class that allows Beam to transform the results of a Bigquery
* query into a standard Java representation, giving us the type guarantees and ease of manipulation
* Bigquery lacks, while localizing any Bigquery-side failures to the {@link #parseFromRecord}
* function.
* <p>This is a trivially serializable class that allows Beam to transform the results of a Cloud
* SQL query into a standard Java representation, giving us the type guarantees and ease of
* manipulation Cloud SQL lacks.
*/
@AutoValue
public abstract class BillingEvent implements Serializable {
private static final long serialVersionUID = -3593088371541450077L;
private static final DateTimeFormatter DATE_TIME_FORMATTER =
DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss zzz");
/** The amount we multiply the price for sunrise creates. This is currently a 15% discount. */
private static final double SUNRISE_DISCOUNT_PRICE_MODIFIER = 0.85;
private static final Pattern SYNTHETIC_REGEX = Pattern.compile("SYNTHETIC", Pattern.LITERAL);
private static final ImmutableList<String> FIELD_NAMES =
ImmutableList.of(
@@ -115,67 +106,7 @@ public abstract class BillingEvent implements Serializable {
/** Returns a list of space-delimited flags associated with the event. */
abstract String flags();
/**
* Constructs a {@code BillingEvent} from a {@code SchemaAndRecord}.
*
* @see <a
* href=http://avro.apache.org/docs/1.7.7/api/java/org/apache/avro/generic/GenericData.Record.html>
* Apache AVRO GenericRecord</a>
*/
static BillingEvent parseFromRecord(SchemaAndRecord schemaAndRecord) {
checkFieldsNotNull(FIELD_NAMES, schemaAndRecord);
GenericRecord record = schemaAndRecord.getRecord();
String flags = extractField(record, "flags");
double amount = getDiscountedAmount(Double.parseDouble(extractField(record, "amount")), flags);
return create(
// We need to chain parsers off extractField because GenericRecord only returns
// Objects, which contain a string representation of their underlying types.
Long.parseLong(extractField(record, "id")),
// Bigquery provides UNIX timestamps with microsecond precision.
new DateTime(Long.parseLong(extractField(record, "billingTime")) / 1000, DateTimeZone.UTC),
new DateTime(Long.parseLong(extractField(record, "eventTime")) / 1000, DateTimeZone.UTC),
extractField(record, "registrarId"),
extractField(record, "billingId"),
extractField(record, "poNumber"),
extractField(record, "tld"),
extractField(record, "action"),
extractField(record, "domain"),
extractField(record, "repositoryId"),
Integer.parseInt(extractField(record, "years")),
extractField(record, "currency"),
amount,
flags);
}
/**
* Applies a discount to sunrise creates and anchor tenant creates if applicable.
*
* Currently sunrise creates are discounted 15% and anchor tenant creates are free for 2 years.
* All anchor tenant creates are enforced to be 2 years in
* {@link google.registry.flows.domain.DomainCreateFlow#verifyAnchorTenantValidPeriod}.
*/
private static double getDiscountedAmount(double amount, String flags) {
// Apply a configurable discount to sunrise creates.
if (flags.contains(Flag.SUNRISE.name())) {
amount =
Double.parseDouble(
new DecimalFormat("#.##").format(amount * SUNRISE_DISCOUNT_PRICE_MODIFIER));
}
// Anchor tenant creates are free for the initial create. This is enforced to be a 2 year period
// upon domain create.
if (flags.contains(Flag.ANCHOR_TENANT.name())) {
amount = 0;
}
return amount;
}
/**
* Creates a concrete {@code BillingEvent}.
*
* <p>This should only be used outside this class for testing- instances of {@code BillingEvent}
* should otherwise come from {@link #parseFromRecord}.
*/
@VisibleForTesting
/** Creates a concrete {@link BillingEvent}. */
static BillingEvent create(
long id,
DateTime billingTime,
@@ -209,7 +140,7 @@ public abstract class BillingEvent implements Serializable {
}
static String getHeader() {
return FIELD_NAMES.stream().collect(Collectors.joining(","));
return String.join(",", FIELD_NAMES);
}
/**
@@ -242,7 +173,7 @@ public abstract class BillingEvent implements Serializable {
currency(),
String.format("%.2f", amount()),
// Strip out the 'synthetic' flag, which is internal only.
flags().replace("SYNTHETIC", "").trim()));
SYNTHETIC_REGEX.matcher(flags()).replaceAll("").trim()));
}
/** Returns the grouping key for this {@code BillingEvent}, to generate the overall invoice. */
@@ -274,6 +205,8 @@ public abstract class BillingEvent implements Serializable {
@AutoValue
abstract static class InvoiceGroupingKey implements Serializable {
private static final long serialVersionUID = -151561764235256205L;
private static final ImmutableList<String> INVOICE_HEADERS =
ImmutableList.of(
"StartDate",
@@ -345,6 +278,8 @@ public abstract class BillingEvent implements Serializable {
/** Coder that provides deterministic (de)serialization for {@code InvoiceGroupingKey}. */
static class InvoiceGroupingKeyCoder extends AtomicCoder<InvoiceGroupingKey> {
private static final long serialVersionUID = 6680701524304107547L;
@Override
public void encode(InvoiceGroupingKey value, OutputStream outStream) throws IOException {
Coder<String> stringCoder = StringUtf8Coder.of();
@@ -24,16 +24,14 @@ import google.registry.beam.common.RegistryJpaIO.Read;
import google.registry.beam.invoicing.BillingEvent.InvoiceGroupingKey;
import google.registry.beam.invoicing.BillingEvent.InvoiceGroupingKey.InvoiceGroupingKeyCoder;
import google.registry.model.billing.BillingEvent.Flag;
import google.registry.model.billing.BillingEvent.OneTime;
import google.registry.model.registrar.Registrar;
import google.registry.persistence.PersistenceModule.TransactionIsolationLevel;
import google.registry.reporting.billing.BillingModule;
import google.registry.util.DomainNameUtils;
import google.registry.util.SqlTemplate;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
import java.util.Optional;
import java.util.regex.Pattern;
@@ -66,8 +64,7 @@ import org.joda.money.CurrencyUnit;
*/
public class InvoicingPipeline implements Serializable {
private static final DateTimeFormatter TIMESTAMP_FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS");
private static final long serialVersionUID = 5386330443625580081L;
private static final Pattern SQL_COMMENT_REGEX =
Pattern.compile("^\\s*--.*\\n", Pattern.MULTILINE);
@@ -107,8 +104,7 @@ public class InvoicingPipeline implements Serializable {
}
private static Optional<BillingEvent> parseRow(Object[] row) {
google.registry.model.billing.BillingEvent.OneTime oneTime =
(google.registry.model.billing.BillingEvent.OneTime) row[0];
OneTime oneTime = (OneTime) row[0];
Registrar registrar = (Registrar) row[1];
CurrencyUnit currency = oneTime.getCost().getCurrencyUnit();
if (!registrar.getBillingAccountMap().containsKey(currency)) {
@@ -140,6 +136,9 @@ public class InvoicingPipeline implements Serializable {
/** Transform that converts a {@code BillingEvent} into an invoice CSV row. */
private static class GenerateInvoiceRows
extends PTransform<PCollection<BillingEvent>, PCollection<String>> {
private static final long serialVersionUID = -8090619008258393728L;
@Override
public PCollection<String> expand(PCollection<BillingEvent> input) {
return input
@@ -203,32 +202,13 @@ public class InvoicingPipeline implements Serializable {
TextIO.sink().withHeader(BillingEvent.getHeader())));
}
/** Create the Bigquery query for a given project and yearMonth at runtime. */
static String makeQuery(String yearMonth, String projectId) {
// Get the timestamp endpoints capturing the entire month with microsecond precision
YearMonth reportingMonth = YearMonth.parse(yearMonth);
LocalDateTime firstMoment = reportingMonth.atDay(1).atTime(LocalTime.MIDNIGHT);
LocalDateTime lastMoment = reportingMonth.atEndOfMonth().atTime(LocalTime.MAX);
// Construct the month's query by filling in the billing_events.sql template
return SqlTemplate.create(getQueryFromFile(InvoicingPipeline.class, "billing_events.sql"))
.put("FIRST_TIMESTAMP_OF_MONTH", firstMoment.format(TIMESTAMP_FORMATTER))
.put("LAST_TIMESTAMP_OF_MONTH", lastMoment.format(TIMESTAMP_FORMATTER))
.put("PROJECT_ID", projectId)
.put("DATASTORE_EXPORT_DATA_SET", "latest_datastore_export")
.put("ONETIME_TABLE", "OneTime")
.put("REGISTRY_TABLE", "Registry")
.put("REGISTRAR_TABLE", "Registrar")
.put("CANCELLATION_TABLE", "Cancellation")
.build();
}
/** Create the Cloud SQL query for a given yearMonth at runtime. */
static String makeCloudSqlQuery(String yearMonth) {
YearMonth endMonth = YearMonth.parse(yearMonth).plusMonths(1);
String queryWithComments =
SqlTemplate.create(
getQueryFromFile(InvoicingPipeline.class, "cloud_sql_billing_events.sql"))
.put("FIRST_TIMESTAMP_OF_MONTH", yearMonth.concat("-01"))
.put("FIRST_TIMESTAMP_OF_MONTH", yearMonth + "-01")
.put(
"LAST_TIMESTAMP_OF_MONTH",
String.format("%d-%d-01", endMonth.getYear(), endMonth.getMonthValue()))
@@ -47,7 +47,7 @@ import google.registry.gcs.GcsUtils;
import google.registry.model.EppResource;
import google.registry.model.contact.ContactHistory;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.host.HostHistory;
import google.registry.model.host.HostResource;
@@ -132,7 +132,7 @@ import org.joda.time.DateTime;
* that are soft-deleted by watermark. The history is emitted as pairs of (resource repo ID: history
* revision ID) from the SQL query.
*
* <h3>{@link DomainBase}</h3>
* <h3>{@link Domain}</h3>
*
* After the most recent (live) domain resources are loaded from the corresponding history objects,
* we marshall them to deposit fragments and emit the (pending deposit: deposit fragment) pairs for
@@ -195,7 +195,7 @@ public class RdePipeline implements Serializable {
private static final ImmutableMap<Class<? extends HistoryEntry>, String> EPP_RESOURCE_FIELD_NAME =
ImmutableMap.of(
DomainHistory.class,
"domainContent",
"domainBase",
ContactHistory.class,
"contactBase",
HostHistory.class,
@@ -477,8 +477,8 @@ public class RdePipeline implements Serializable {
public void processElement(
@Element KV<String, Long> kv, MultiOutputReceiver receiver) {
activeDomainCounter.inc();
DomainBase domain =
(DomainBase)
Domain domain =
(Domain)
loadResourceByHistoryEntryId(
DomainHistory.class, kv.getKey(), kv.getValue());
pendingDeposits.stream()
@@ -654,8 +654,8 @@ public class RdePipeline implements Serializable {
TypeDescriptor.of(DepositFragment.class)))
.via(
(KV<String, CoGbkResult> kv) -> {
DomainBase superordinateDomain =
(DomainBase)
Domain superordinateDomain =
(Domain)
loadResourceByHistoryEntryId(
DomainHistory.class,
kv.getKey(),
@@ -23,6 +23,7 @@ import google.registry.beam.common.RegistryJpaIO;
import google.registry.beam.common.RegistryJpaIO.Read;
import google.registry.model.EppResource;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainBase;
import google.registry.model.host.HostResource;
import google.registry.persistence.PersistenceModule.TransactionIsolationLevel;
@@ -51,7 +52,7 @@ import org.joda.time.DateTime;
public class ResaveAllEppResourcesPipeline implements Serializable {
private static final ImmutableSet<Class<? extends EppResource>> EPP_RESOURCE_CLASSES =
ImmutableSet.of(ContactResource.class, DomainBase.class, HostResource.class);
ImmutableSet.of(ContactResource.class, Domain.class, HostResource.class);
/**
* There exist three possible situations where we know we'll want to project domains to the
@@ -111,16 +112,16 @@ public class ResaveAllEppResourcesPipeline implements Serializable {
* transfers, grace periods).
*
* <p>The logic of what might have changed is paraphrased from {@link
* google.registry.model.domain.DomainContent#cloneProjectedAtTime(DateTime)}.
* DomainBase#cloneProjectedAtTime(DateTime)}.
*/
private void fastResaveDomains(Pipeline pipeline) {
Read<DomainBase, DomainBase> read =
Read<Domain, Domain> read =
RegistryJpaIO.read(
DOMAINS_TO_PROJECT_QUERY,
ImmutableMap.of("END_OF_TIME", DateTimeUtils.END_OF_TIME),
DomainBase.class,
Domain.class,
d -> d);
projectAndResaveResources(pipeline, DomainBase.class, read);
projectAndResaveResources(pipeline, Domain.class, read);
}
/** Projects all resources to the current time and saves them. */
@@ -26,7 +26,7 @@ import google.registry.beam.common.RegistryJpaIO;
import google.registry.beam.common.RegistryJpaIO.Read;
import google.registry.beam.spec11.SafeBrowsingTransforms.EvaluateSafeBrowsingFn;
import google.registry.config.RegistryConfig.ConfigModule;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.reporting.Spec11ThreatMatch;
import google.registry.model.reporting.Spec11ThreatMatch.ThreatType;
import google.registry.persistence.PersistenceModule.TransactionIsolationLevel;
@@ -127,22 +127,21 @@ public class Spec11Pipeline implements Serializable {
@ProcessElement
public void processElement(
@Element KV<String, String> input, OutputReceiver<DomainNameInfo> output) {
DomainBase domainBase =
Domain domain =
jpaTm()
.transact(
() ->
jpaTm()
.loadByKey(
VKey.createSql(DomainBase.class, input.getKey())));
.loadByKey(VKey.createSql(Domain.class, input.getKey())));
String emailAddress = input.getValue();
if (emailAddress == null) {
emailAddress = "";
}
DomainNameInfo domainNameInfo =
DomainNameInfo.create(
domainBase.getDomainName(),
domainBase.getRepoId(),
domainBase.getCurrentSponsorRegistrarId(),
domain.getDomainName(),
domain.getRepoId(),
domain.getCurrentSponsorRegistrarId(),
emailAddress);
output.output(domainNameInfo);
}
@@ -20,7 +20,7 @@ import google.registry.dns.DnsConstants.TargetType;
import google.registry.model.EppResource;
import google.registry.model.EppResource.ForeignKeyedEppResource;
import google.registry.model.annotations.ExternalMessagingName;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.host.HostResource;
import google.registry.request.Action;
import google.registry.request.HttpException.BadRequestException;
@@ -62,7 +62,7 @@ public final class RefreshDnsAction implements Runnable {
}
switch (type) {
case DOMAIN:
loadAndVerifyExistence(DomainBase.class, domainOrHostName);
loadAndVerifyExistence(Domain.class, domainOrHostName);
dnsQueue.addDomainRefreshTask(domainOrHostName);
break;
case HOST:
@@ -36,7 +36,7 @@ import google.registry.config.RegistryConfig.Config;
import google.registry.dns.writer.BaseDnsWriter;
import google.registry.dns.writer.DnsWriter;
import google.registry.dns.writer.DnsWriterZone;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.host.HostResource;
import google.registry.model.tld.Registries;
@@ -121,13 +121,12 @@ public class CloudDnsWriter extends BaseDnsWriter {
String absoluteDomainName = getAbsoluteHostName(domainName);
// Load the target domain. Note that it can be absent if this domain was just deleted.
Optional<DomainBase> domainBase =
loadByForeignKey(DomainBase.class, domainName, clock.nowUtc());
Optional<Domain> domain = loadByForeignKey(Domain.class, domainName, clock.nowUtc());
// Return early if no DNS records should be published.
// desiredRecordsBuilder is populated with an empty set to indicate that all existing records
// should be deleted.
if (!domainBase.isPresent() || !domainBase.get().shouldPublishToDns()) {
if (!domain.isPresent() || !domain.get().shouldPublishToDns()) {
desiredRecords.put(absoluteDomainName, ImmutableSet.of());
return;
}
@@ -135,7 +134,7 @@ public class CloudDnsWriter extends BaseDnsWriter {
ImmutableSet.Builder<ResourceRecordSet> domainRecords = new ImmutableSet.Builder<>();
// Construct DS records (if any).
Set<DelegationSignerData> dsData = domainBase.get().getDsData();
Set<DelegationSignerData> dsData = domain.get().getDsData();
if (!dsData.isEmpty()) {
HashSet<String> dsRrData = new HashSet<>();
for (DelegationSignerData ds : dsData) {
@@ -154,8 +153,8 @@ public class CloudDnsWriter extends BaseDnsWriter {
}
// Construct NS records (if any).
Set<String> nameserverData = domainBase.get().loadNameserverHostNames();
Set<String> subordinateHosts = domainBase.get().getSubordinateHosts();
Set<String> nameserverData = domain.get().loadNameserverHostNames();
Set<String> subordinateHosts = domain.get().getSubordinateHosts();
if (!nameserverData.isEmpty()) {
HashSet<String> nsRrData = new HashSet<>();
for (String hostName : nameserverData) {
@@ -27,7 +27,7 @@ import com.google.common.net.InternetDomainName;
import google.registry.config.RegistryConfig.Config;
import google.registry.dns.writer.BaseDnsWriter;
import google.registry.dns.writer.DnsWriterZone;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.host.HostResource;
import google.registry.model.tld.Registries;
@@ -127,12 +127,11 @@ public class DnsUpdateWriter extends BaseDnsWriter {
* this domain refresh request
*/
private void publishDomain(String domainName, String requestingHostName) {
Optional<DomainBase> domainOptional =
loadByForeignKey(DomainBase.class, domainName, clock.nowUtc());
Optional<Domain> domainOptional = loadByForeignKey(Domain.class, domainName, clock.nowUtc());
update.delete(toAbsoluteName(domainName), Type.ANY);
// If the domain is now deleted, then don't update DNS for it.
if (domainOptional.isPresent()) {
DomainBase domain = domainOptional.get();
Domain domain = domainOptional.get();
// As long as the domain exists, orphan glues should be cleaned.
deleteSubordinateHostAddressSet(domain, requestingHostName, update);
if (domain.shouldPublishToDns()) {
@@ -184,7 +183,7 @@ public class DnsUpdateWriter extends BaseDnsWriter {
}
}
private RRset makeDelegationSignerSet(DomainBase domain) {
private RRset makeDelegationSignerSet(Domain domain) {
RRset signerSet = new RRset();
for (DelegationSignerData signerData : domain.getDsData()) {
DSRecord dsRecord =
@@ -202,7 +201,7 @@ public class DnsUpdateWriter extends BaseDnsWriter {
}
private void deleteSubordinateHostAddressSet(
DomainBase domain, String additionalHost, Update update) {
Domain domain, String additionalHost, Update update) {
for (String hostName :
union(
domain.getSubordinateHosts(),
@@ -213,7 +212,7 @@ public class DnsUpdateWriter extends BaseDnsWriter {
}
}
private void addInBailiwickNameServerSet(DomainBase domain, Update update) {
private void addInBailiwickNameServerSet(Domain domain, Update update) {
for (String hostName :
intersection(domain.loadNameserverHostNames(), domain.getSubordinateHosts())) {
Optional<HostResource> host = loadByForeignKey(HostResource.class, hostName, clock.nowUtc());
@@ -223,7 +222,7 @@ public class DnsUpdateWriter extends BaseDnsWriter {
}
}
private RRset makeNameServerSet(DomainBase domain) {
private RRset makeNameServerSet(Domain domain) {
RRset nameServerSet = new RRset();
for (String hostName : domain.loadNameserverHostNames()) {
NSRecord record =
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>backend</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4</instance-class>
<basic-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>default</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4</instance-class>
<basic-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>pubapi</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4</instance-class>
<basic-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>tools</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4</instance-class>
<basic-scaling>
@@ -6,22 +6,22 @@
<property name="searchName" direction="asc"/>
</datastore-index>
<!-- For finding domain resources by registrar. -->
<datastore-index kind="DomainBase" ancestor="false" source="manual">
<datastore-index kind="Domain" ancestor="false" source="manual">
<property name="currentSponsorClientId" direction="asc"/>
<property name="deletionTime" direction="asc"/>
</datastore-index>
<!-- For finding domain resources by TLD. -->
<datastore-index kind="DomainBase" ancestor="false" source="manual">
<datastore-index kind="Domain" ancestor="false" source="manual">
<property name="tld" direction="asc"/>
<property name="deletionTime" direction="asc"/>
</datastore-index>
<!-- For finding domain resources by registrar. -->
<datastore-index kind="DomainBase" ancestor="false" source="manual">
<datastore-index kind="Domain" ancestor="false" source="manual">
<property name="currentSponsorClientId" direction="asc"/>
<property name="deletionTime" direction="asc"/>
</datastore-index>
<!-- For finding the most recently created domain resources. -->
<datastore-index kind="DomainBase" ancestor="false" source="manual">
<datastore-index kind="Domain" ancestor="false" source="manual">
<property name="tld" direction="asc"/>
<property name="creationTime" direction="desc"/>
</datastore-index>
@@ -32,22 +32,22 @@
<property name="fullyQualifiedHostName" direction="asc"/>
</datastore-index>
<!-- For determining the active domains linked to a given contact. -->
<datastore-index kind="DomainBase" ancestor="false" source="manual">
<datastore-index kind="Domain" ancestor="false" source="manual">
<property name="allContacts.contact" direction="asc"/>
<property name="deletionTime" direction="asc"/>
</datastore-index>
<!-- For determining the active domains linked to a given host. -->
<datastore-index kind="DomainBase" ancestor="false" source="manual">
<datastore-index kind="Domain" ancestor="false" source="manual">
<property name="nsHosts" direction="asc"/>
<property name="deletionTime" direction="asc"/>
</datastore-index>
<!-- For deleting expired not-previously-deleted domains. -->
<datastore-index kind="DomainBase" ancestor="false" source="manual">
<datastore-index kind="Domain" ancestor="false" source="manual">
<property name="deletionTime" direction="asc"/>
<property name="autorenewEndTime" direction="asc"/>
</datastore-index>
<!-- For RDAP searches by linked nameserver. -->
<datastore-index kind="DomainBase" ancestor="false" source="manual">
<datastore-index kind="Domain" ancestor="false" source="manual">
<property name="nsHosts" direction="asc"/>
<property name="deletionTime" direction="asc"/>
</datastore-index>
@@ -74,16 +74,16 @@
<property name="modificationTime" direction="asc"/>
</datastore-index>
<!-- For RDAP. -->
<datastore-index kind="DomainBase" ancestor="false" source="manual">
<datastore-index kind="Domain" ancestor="false" source="manual">
<property name="currentSponsorClientId" direction="asc"/>
<property name="fullyQualifiedDomainName" direction="asc"/>
</datastore-index>
<datastore-index kind="DomainBase" ancestor="false" source="manual">
<datastore-index kind="Domain" ancestor="false" source="manual">
<property name="currentSponsorClientId" direction="asc"/>
<property name="tld" direction="asc"/>
<property name="fullyQualifiedDomainName" direction="asc"/>
</datastore-index>
<datastore-index kind="DomainBase" ancestor="false" source="manual">
<datastore-index kind="Domain" ancestor="false" source="manual">
<property name="tld" direction="asc"/>
<property name="fullyQualifiedDomainName" direction="asc"/>
</datastore-index>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>backend</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4</instance-class>
<basic-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>default</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4_1G</instance-class>
<basic-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>pubapi</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4</instance-class>
<basic-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>tools</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4</instance-class>
<basic-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>backend</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4</instance-class>
<basic-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>default</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4_1G</instance-class>
<basic-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>pubapi</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4</instance-class>
<basic-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>tools</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4</instance-class>
<basic-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>backend</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4_1G</instance-class>
<basic-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>default</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4_1G</instance-class>
<manual-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>pubapi</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4_1G</instance-class>
<manual-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>tools</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4_1G</instance-class>
<basic-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>backend</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4</instance-class>
<basic-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>default</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>F4_1G</instance-class>
<automatic-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>pubapi</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4</instance-class>
<basic-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>tools</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4</instance-class>
<basic-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>backend</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4</instance-class>
<basic-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>default</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4_1G</instance-class>
<manual-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>pubapi</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4_1G</instance-class>
<manual-scaling>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<runtime>java17</runtime>
<app-engine-apis>true</app-engine-apis>
<runtime>java8</runtime>
<service>tools</service>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<instance-class>B4</instance-class>
<basic-scaling>
@@ -44,7 +44,7 @@ import dagger.Module;
import dagger.Provides;
import google.registry.flows.domain.DomainFlowUtils.BadCommandForRegistryPhaseException;
import google.registry.flows.domain.DomainFlowUtils.InvalidIdnDomainLabelException;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.index.ForeignKeyIndex;
import google.registry.model.tld.Registry;
import google.registry.model.tld.label.ReservationType;
@@ -156,8 +156,7 @@ public class CheckApiAction implements Runnable {
}
private boolean checkExists(String domainString, DateTime now) {
return !ForeignKeyIndex.loadCached(DomainBase.class, ImmutableList.of(domainString), now)
.isEmpty();
return !ForeignKeyIndex.loadCached(Domain.class, ImmutableList.of(domainString), now).isEmpty();
}
private Optional<String> checkReserved(InternetDomainName domainName) {
@@ -39,8 +39,8 @@ import google.registry.model.EppResource;
import google.registry.model.EppResource.ForeignKeyedEppResource;
import google.registry.model.EppResource.ResourceWithTransferData;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainContent;
import google.registry.model.domain.Period;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.eppcommon.AuthInfo;
@@ -147,7 +147,7 @@ public final class ResourceFlowUtils {
}
/** Check that the given AuthInfo is either missing or else is valid for the given resource. */
public static void verifyOptionalAuthInfo(Optional<AuthInfo> authInfo, DomainBase domain)
public static void verifyOptionalAuthInfo(Optional<AuthInfo> authInfo, Domain domain)
throws EppException {
if (authInfo.isPresent()) {
verifyAuthInfo(authInfo.get(), domain);
@@ -155,7 +155,7 @@ public final class ResourceFlowUtils {
}
/** Check that the given {@link AuthInfo} is valid for the given domain. */
public static void verifyAuthInfo(AuthInfo authInfo, DomainBase domain) throws EppException {
public static void verifyAuthInfo(AuthInfo authInfo, Domain domain) throws EppException {
final String authRepoId = authInfo.getPw().getRepoId();
String authPassword = authInfo.getPw().getValue();
if (authRepoId == null) {
@@ -236,7 +236,7 @@ public final class ResourceFlowUtils {
* @param domain is the domain already projected at approvalTime
*/
public static DateTime computeExDateForApprovalTime(
DomainContent domain, DateTime approvalTime, Period period) {
DomainBase domain, DateTime approvalTime, Period period) {
boolean inAutoRenew = domain.getGracePeriodStatuses().contains(GracePeriodStatus.AUTO_RENEW);
// inAutoRenew is set to false if the period is zero because a zero-period transfer should not
// subsume an autorenew.
@@ -246,7 +246,7 @@ public final class ResourceFlowUtils {
if (period.getValue() == 0) {
inAutoRenew = false;
}
return DomainBase.extendRegistrationWithCap(
return Domain.extendRegistrationWithCap(
approvalTime,
domain.getRegistrationExpirationTime(),
period.getValue() - (inAutoRenew ? 1 : 0));
@@ -22,7 +22,7 @@ import google.registry.flows.FlowMetadata;
import google.registry.flows.SessionMetadata;
import google.registry.flows.domain.DomainCreateFlow;
import google.registry.model.ImmutableObject;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.eppinput.EppInput;
import google.registry.model.eppoutput.EppResponse.ResponseData;
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
@@ -125,10 +125,9 @@ public class DomainCreateFlowCustomLogic extends BaseFlowCustomLogic {
public abstract static class BeforeSaveParameters extends ImmutableObject {
/**
* The new {@link DomainBase} entity that is going to be persisted at the end of the
* transaction.
* The new {@link Domain} entity that is going to be persisted at the end of the transaction.
*/
public abstract DomainBase newDomain();
public abstract Domain newDomain();
/**
* The new {@link HistoryEntry} entity for the domain's creation that is going to be persisted
@@ -162,7 +161,7 @@ public class DomainCreateFlowCustomLogic extends BaseFlowCustomLogic {
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder setNewDomain(DomainBase newDomain);
public abstract Builder setNewDomain(Domain newDomain);
public abstract Builder setHistoryEntry(HistoryEntry historyEntry);
@@ -21,7 +21,7 @@ import google.registry.flows.FlowMetadata;
import google.registry.flows.SessionMetadata;
import google.registry.flows.domain.DomainDeleteFlow;
import google.registry.model.ImmutableObject;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.eppinput.EppInput;
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
import google.registry.model.eppoutput.Result;
@@ -83,7 +83,7 @@ public class DomainDeleteFlowCustomLogic extends BaseFlowCustomLogic {
@AutoValue
public abstract static class AfterValidationParameters extends ImmutableObject {
public abstract DomainBase existingDomain();
public abstract Domain existingDomain();
public static Builder newBuilder() {
return new AutoValue_DomainDeleteFlowCustomLogic_AfterValidationParameters.Builder();
@@ -93,7 +93,7 @@ public class DomainDeleteFlowCustomLogic extends BaseFlowCustomLogic {
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder setExistingDomain(DomainBase existingDomain);
public abstract Builder setExistingDomain(Domain existingDomain);
public abstract AfterValidationParameters build();
}
@@ -109,9 +109,9 @@ public class DomainDeleteFlowCustomLogic extends BaseFlowCustomLogic {
@AutoValue
public abstract static class BeforeSaveParameters extends ImmutableObject {
public abstract DomainBase existingDomain();
public abstract Domain existingDomain();
public abstract DomainBase newDomain();
public abstract Domain newDomain();
public abstract HistoryEntry historyEntry();
@@ -125,9 +125,9 @@ public class DomainDeleteFlowCustomLogic extends BaseFlowCustomLogic {
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder setExistingDomain(DomainBase existingDomain);
public abstract Builder setExistingDomain(Domain existingDomain);
public abstract Builder setNewDomain(DomainBase newDomain);
public abstract Builder setNewDomain(Domain newDomain);
public abstract Builder setHistoryEntry(HistoryEntry historyEntry);
@@ -21,7 +21,7 @@ import google.registry.flows.FlowMetadata;
import google.registry.flows.SessionMetadata;
import google.registry.flows.domain.DomainInfoFlow;
import google.registry.model.ImmutableObject;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainInfoData;
import google.registry.model.eppinput.EppInput;
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
@@ -53,8 +53,8 @@ public class DomainInfoFlowCustomLogic extends BaseFlowCustomLogic {
/**
* A hook that runs before the response is returned.
*
* <p>This takes the {@link DomainBase} and {@link ResponseExtension}s as input and returns
* them, potentially with modifications.
* <p>This takes the {@link Domain} and {@link ResponseExtension}s as input and returns them,
* potentially with modifications.
*/
@SuppressWarnings("unused")
public BeforeResponseReturnData beforeResponse(BeforeResponseParameters parameters)
@@ -69,7 +69,7 @@ public class DomainInfoFlowCustomLogic extends BaseFlowCustomLogic {
@AutoValue
public abstract static class AfterValidationParameters extends ImmutableObject {
public abstract DomainBase domain();
public abstract Domain domain();
public static Builder newBuilder() {
return new AutoValue_DomainInfoFlowCustomLogic_AfterValidationParameters.Builder();
@@ -79,7 +79,7 @@ public class DomainInfoFlowCustomLogic extends BaseFlowCustomLogic {
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder setDomain(DomainBase domain);
public abstract Builder setDomain(Domain domain);
public abstract AfterValidationParameters build();
}
@@ -89,7 +89,7 @@ public class DomainInfoFlowCustomLogic extends BaseFlowCustomLogic {
@AutoValue
public abstract static class BeforeResponseParameters extends ImmutableObject {
public abstract DomainBase domain();
public abstract Domain domain();
public abstract DomainInfoData resData();
@@ -103,7 +103,7 @@ public class DomainInfoFlowCustomLogic extends BaseFlowCustomLogic {
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder setDomain(DomainBase domain);
public abstract Builder setDomain(Domain domain);
public abstract Builder setResData(DomainInfoData resData);
@@ -21,7 +21,7 @@ import google.registry.flows.FlowMetadata;
import google.registry.flows.SessionMetadata;
import google.registry.flows.domain.DomainRenewFlow;
import google.registry.model.ImmutableObject;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.eppinput.EppInput;
import google.registry.model.eppoutput.EppResponse.ResponseData;
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
@@ -68,8 +68,8 @@ public class DomainRenewFlowCustomLogic extends BaseFlowCustomLogic {
/**
* A hook that runs before the response is returned.
*
* <p>This takes the {@link DomainBase} and {@link ResponseExtension}s as input and returns
* them, potentially with modifications.
* <p>This takes the {@link Domain} and {@link ResponseExtension}s as input and returns them,
* potentially with modifications.
*/
@SuppressWarnings("unused")
public BeforeResponseReturnData beforeResponse(BeforeResponseParameters parameters)
@@ -84,7 +84,7 @@ public class DomainRenewFlowCustomLogic extends BaseFlowCustomLogic {
@AutoValue
public abstract static class AfterValidationParameters extends ImmutableObject {
public abstract DomainBase existingDomain();
public abstract Domain existingDomain();
public abstract int years();
@@ -98,7 +98,7 @@ public class DomainRenewFlowCustomLogic extends BaseFlowCustomLogic {
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder setExistingDomain(DomainBase existingDomain);
public abstract Builder setExistingDomain(Domain existingDomain);
public abstract Builder setYears(int years);
@@ -118,9 +118,9 @@ public class DomainRenewFlowCustomLogic extends BaseFlowCustomLogic {
@AutoValue
public abstract static class BeforeSaveParameters extends ImmutableObject {
public abstract DomainBase existingDomain();
public abstract Domain existingDomain();
public abstract DomainBase newDomain();
public abstract Domain newDomain();
public abstract HistoryEntry historyEntry();
@@ -138,9 +138,9 @@ public class DomainRenewFlowCustomLogic extends BaseFlowCustomLogic {
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder setExistingDomain(DomainBase existingDomain);
public abstract Builder setExistingDomain(Domain existingDomain);
public abstract Builder setNewDomain(DomainBase newDomain);
public abstract Builder setNewDomain(Domain newDomain);
public abstract Builder setHistoryEntry(HistoryEntry historyEntry);
@@ -158,7 +158,7 @@ public class DomainRenewFlowCustomLogic extends BaseFlowCustomLogic {
@AutoValue
public abstract static class BeforeResponseParameters extends ImmutableObject {
public abstract DomainBase domain();
public abstract Domain domain();
public abstract ResponseData resData();
@@ -172,7 +172,7 @@ public class DomainRenewFlowCustomLogic extends BaseFlowCustomLogic {
@AutoValue.Builder
public abstract static class Builder {
public abstract BeforeResponseParameters.Builder setDomain(DomainBase domain);
public abstract BeforeResponseParameters.Builder setDomain(Domain domain);
public abstract BeforeResponseParameters.Builder setResData(ResponseData resData);
@@ -20,7 +20,7 @@ import google.registry.flows.FlowMetadata;
import google.registry.flows.SessionMetadata;
import google.registry.flows.domain.DomainUpdateFlow;
import google.registry.model.ImmutableObject;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.eppinput.EppInput;
import google.registry.model.reporting.HistoryEntry;
@@ -65,7 +65,7 @@ public class DomainUpdateFlowCustomLogic extends BaseFlowCustomLogic {
@AutoValue
public abstract static class AfterValidationParameters extends ImmutableObject {
public abstract DomainBase existingDomain();
public abstract Domain existingDomain();
public static Builder newBuilder() {
return new AutoValue_DomainUpdateFlowCustomLogic_AfterValidationParameters.Builder();
@@ -75,7 +75,7 @@ public class DomainUpdateFlowCustomLogic extends BaseFlowCustomLogic {
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder setExistingDomain(DomainBase existingDomain);
public abstract Builder setExistingDomain(Domain existingDomain);
public abstract AfterValidationParameters build();
}
@@ -91,9 +91,9 @@ public class DomainUpdateFlowCustomLogic extends BaseFlowCustomLogic {
@AutoValue
public abstract static class BeforeSaveParameters extends ImmutableObject {
public abstract DomainBase existingDomain();
public abstract Domain existingDomain();
public abstract DomainBase newDomain();
public abstract Domain newDomain();
public abstract HistoryEntry historyEntry();
@@ -107,9 +107,9 @@ public class DomainUpdateFlowCustomLogic extends BaseFlowCustomLogic {
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder setExistingDomain(DomainBase existingDomain);
public abstract Builder setExistingDomain(Domain existingDomain);
public abstract Builder setNewDomain(DomainBase newDomain);
public abstract Builder setNewDomain(Domain newDomain);
public abstract Builder setHistoryEntry(HistoryEntry historyEntry);
@@ -54,7 +54,7 @@ import google.registry.flows.domain.token.AllocationTokenDomainCheckResults;
import google.registry.flows.domain.token.AllocationTokenFlowUtils;
import google.registry.model.EppResource;
import google.registry.model.billing.BillingEvent;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainCommand.Check;
import google.registry.model.domain.fee.FeeCheckCommandExtension;
import google.registry.model.domain.fee.FeeCheckCommandExtensionItem;
@@ -169,8 +169,8 @@ public final class DomainCheckFlow implements Flow {
// TODO: Use as of date from fee extension v0.12 instead of now, if specified.
.setAsOfDate(now)
.build());
ImmutableMap<String, ForeignKeyIndex<DomainBase>> existingDomains =
ForeignKeyIndex.load(DomainBase.class, domainNames, now);
ImmutableMap<String, ForeignKeyIndex<Domain>> existingDomains =
ForeignKeyIndex.load(Domain.class, domainNames, now);
Optional<AllocationTokenExtension> allocationTokenExtension =
eppInput.getSingleExtension(AllocationTokenExtension.class);
Optional<AllocationTokenDomainCheckResults> tokenDomainCheckResults =
@@ -227,7 +227,7 @@ public final class DomainCheckFlow implements Flow {
private Optional<String> getMessageForCheck(
InternetDomainName domainName,
ImmutableMap<String, ForeignKeyIndex<DomainBase>> existingDomains,
ImmutableMap<String, ForeignKeyIndex<Domain>> existingDomains,
ImmutableMap<InternetDomainName, String> tokenCheckResults,
ImmutableMap<String, TldState> tldStates,
Optional<AllocationToken> allocationToken) {
@@ -251,7 +251,7 @@ public final class DomainCheckFlow implements Flow {
/** Handle the fee check extension. */
private ImmutableList<? extends ResponseExtension> getResponseExtensions(
ImmutableMap<String, InternetDomainName> domainNames,
ImmutableMap<String, ForeignKeyIndex<DomainBase>> existingDomains,
ImmutableMap<String, ForeignKeyIndex<Domain>> existingDomains,
ImmutableSet<String> availableDomains,
DateTime now,
Optional<AllocationToken> allocationToken)
@@ -264,7 +264,7 @@ public final class DomainCheckFlow implements Flow {
FeeCheckCommandExtension<?, ?> feeCheck = feeCheckOpt.get();
ImmutableList.Builder<FeeCheckResponseExtensionItem> responseItems =
new ImmutableList.Builder<>();
ImmutableMap<String, DomainBase> domainObjs =
ImmutableMap<String, Domain> domainObjs =
loadDomainsForRestoreChecks(feeCheck, domainNames, existingDomains);
ImmutableMap<String, BillingEvent.Recurring> recurrences =
loadRecurrencesForDomains(domainObjs);
@@ -272,12 +272,12 @@ public final class DomainCheckFlow implements Flow {
for (FeeCheckCommandExtensionItem feeCheckItem : feeCheck.getItems()) {
for (String domainName : getDomainNamesToCheckForFee(feeCheckItem, domainNames.keySet())) {
FeeCheckResponseExtensionItem.Builder<?> builder = feeCheckItem.createResponseBuilder();
Optional<DomainBase> domainBase = Optional.ofNullable(domainObjs.get(domainName));
Optional<Domain> domain = Optional.ofNullable(domainObjs.get(domainName));
handleFeeRequest(
feeCheckItem,
builder,
domainNames.get(domainName),
domainBase,
domain,
feeCheck.getCurrency(),
now,
pricingLogic,
@@ -301,10 +301,10 @@ public final class DomainCheckFlow implements Flow {
* nicer in Cloud SQL when we can SELECT just the fields we want rather than having to load the
* entire entity.
*/
private ImmutableMap<String, DomainBase> loadDomainsForRestoreChecks(
private ImmutableMap<String, Domain> loadDomainsForRestoreChecks(
FeeCheckCommandExtension<?, ?> feeCheck,
ImmutableMap<String, InternetDomainName> domainNames,
ImmutableMap<String, ForeignKeyIndex<DomainBase>> existingDomains) {
ImmutableMap<String, ForeignKeyIndex<Domain>> existingDomains) {
ImmutableList<String> restoreCheckDomains;
if (feeCheck instanceof FeeCheckCommandExtensionV06) {
// The V06 fee extension supports specifying the command fees to check on a per-domain basis.
@@ -326,25 +326,25 @@ public final class DomainCheckFlow implements Flow {
}
// Filter down to just domains we know exist and then use the EppResource cache to load them.
ImmutableMap<String, VKey<DomainBase>> existingDomainsToLoad =
ImmutableMap<String, VKey<Domain>> existingDomainsToLoad =
restoreCheckDomains.stream()
.filter(existingDomains::containsKey)
.collect(toImmutableMap(d -> d, d -> existingDomains.get(d).getResourceKey()));
ImmutableMap<VKey<? extends EppResource>, EppResource> loadedDomains =
EppResource.loadCached(ImmutableList.copyOf(existingDomainsToLoad.values()));
return ImmutableMap.copyOf(
Maps.transformEntries(existingDomainsToLoad, (k, v) -> (DomainBase) loadedDomains.get(v)));
Maps.transformEntries(existingDomainsToLoad, (k, v) -> (Domain) loadedDomains.get(v)));
}
private ImmutableMap<String, BillingEvent.Recurring> loadRecurrencesForDomains(
ImmutableMap<String, DomainBase> domainObjs) {
ImmutableMap<String, Domain> domainObjs) {
return tm().transact(
() -> {
ImmutableMap<VKey<? extends BillingEvent.Recurring>, BillingEvent.Recurring>
recurrences =
tm().loadByKeys(
domainObjs.values().stream()
.map(DomainBase::getAutorenewBillingEvent)
.map(Domain::getAutorenewBillingEvent)
.collect(toImmutableSet()));
return ImmutableMap.copyOf(
Maps.transformValues(
@@ -83,7 +83,7 @@ import google.registry.model.billing.BillingEvent.Flag;
import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.billing.BillingEvent.Recurring;
import google.registry.model.billing.BillingEvent.RenewalPriceBehavior;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainCommand;
import google.registry.model.domain.DomainCommand.Create;
import google.registry.model.domain.DomainHistory;
@@ -247,7 +247,7 @@ public final class DomainCreateFlow implements TransactionalFlow {
verifyUnitIsYears(period);
int years = period.getValue();
validateRegistrationPeriod(years);
verifyResourceDoesNotExist(DomainBase.class, targetId, now, registrarId);
verifyResourceDoesNotExist(Domain.class, targetId, now, registrarId);
// Validate that this is actually a legal domain name on a TLD that the registrar has access to.
InternetDomainName domainName = validateDomainName(command.getFullyQualifiedDomainName());
String domainLabel = domainName.parts().get(0);
@@ -333,9 +333,9 @@ public final class DomainCreateFlow implements TransactionalFlow {
validateSecDnsExtension(eppInput.getSingleExtension(SecDnsCreateExtension.class));
DateTime registrationExpirationTime = leapSafeAddYears(now, years);
String repoId = createDomainRepoId(allocateId(), registry.getTldStr());
Key<DomainHistory> domainHistoryKey =
Key.create(Key.create(DomainBase.class, repoId), DomainHistory.class, allocateId());
historyBuilder.setId(domainHistoryKey.getId());
long historyRevisionId = allocateId();
DomainHistoryId domainHistoryId = new DomainHistoryId(repoId, historyRevisionId);
historyBuilder.setId(historyRevisionId);
// Bill for the create.
BillingEvent.OneTime createBillingEvent =
createOneTimeBillingEvent(
@@ -345,17 +345,17 @@ public final class DomainCreateFlow implements TransactionalFlow {
isReserved(domainName, isSunriseCreate),
years,
feesAndCredits,
domainHistoryKey,
domainHistoryId,
allocationToken,
now);
// Create a new autorenew billing event and poll message starting at the expiration time.
BillingEvent.Recurring autorenewBillingEvent =
createAutorenewBillingEvent(
domainHistoryKey,
domainHistoryId,
registrationExpirationTime,
getRenewalPriceInfo(isAnchorTenant, allocationToken, feesAndCredits));
PollMessage.Autorenew autorenewPollMessage =
createAutorenewPollMessage(domainHistoryKey, registrationExpirationTime);
createAutorenewPollMessage(domainHistoryId, registrationExpirationTime);
ImmutableSet.Builder<ImmutableObject> entitiesToSave = new ImmutableSet.Builder<>();
entitiesToSave.add(createBillingEvent, autorenewBillingEvent, autorenewPollMessage);
// Bill for EAP cost, if any.
@@ -368,8 +368,8 @@ public final class DomainCreateFlow implements TransactionalFlow {
reservationTypes.contains(NAME_COLLISION)
? ImmutableSet.of(SERVER_HOLD)
: ImmutableSet.of();
DomainBase domain =
new DomainBase.Builder()
Domain domain =
new Domain.Builder()
.setCreationRegistrarId(registrarId)
.setPersistedCurrentSponsorRegistrarId(registrarId)
.setRepoId(repoId)
@@ -530,7 +530,7 @@ public final class DomainCreateFlow implements TransactionalFlow {
}
private DomainHistory buildDomainHistory(
DomainBase domain, Registry registry, DateTime now, Period period, Duration addGracePeriod) {
Domain domain, Registry registry, DateTime now, Period period, Duration addGracePeriod) {
// We ignore prober transactions
if (registry.getTldType() == TldType.REAL) {
historyBuilder
@@ -552,7 +552,7 @@ public final class DomainCreateFlow implements TransactionalFlow {
boolean isReserved,
int years,
FeesAndCredits feesAndCredits,
Key<DomainHistory> domainHistoryKey,
DomainHistoryId domainHistoryId,
Optional<AllocationToken> allocationToken,
DateTime now) {
ImmutableSet.Builder<Flag> flagsBuilder = new ImmutableSet.Builder<>();
@@ -581,12 +581,12 @@ public final class DomainCreateFlow implements TransactionalFlow {
? registry.getAnchorTenantAddGracePeriodLength()
: registry.getAddGracePeriodLength()))
.setFlags(flagsBuilder.build())
.setParent(domainHistoryKey)
.setDomainHistoryId(domainHistoryId)
.build();
}
private Recurring createAutorenewBillingEvent(
Key<DomainHistory> domainHistoryKey,
DomainHistoryId domainHistoryId,
DateTime registrationExpirationTime,
RenewalPriceInfo renewalpriceInfo) {
return new BillingEvent.Recurring.Builder()
@@ -596,21 +596,20 @@ public final class DomainCreateFlow implements TransactionalFlow {
.setRegistrarId(registrarId)
.setEventTime(registrationExpirationTime)
.setRecurrenceEndTime(END_OF_TIME)
.setParent(domainHistoryKey)
.setDomainHistoryId(domainHistoryId)
.setRenewalPriceBehavior(renewalpriceInfo.renewalPriceBehavior())
.setRenewalPrice(renewalpriceInfo.renewalPrice())
.build();
}
private Autorenew createAutorenewPollMessage(
Key<DomainHistory> domainHistoryKey, DateTime registrationExpirationTime) {
DomainHistoryId domainHistoryId, DateTime registrationExpirationTime) {
return new PollMessage.Autorenew.Builder()
.setTargetId(targetId)
.setRegistrarId(registrarId)
.setEventTime(registrationExpirationTime)
.setMsg("Domain was auto-renewed.")
.setDomainHistoryId(
new DomainHistoryId(domainHistoryKey.getParent().getName(), domainHistoryKey.getId()))
.setDomainHistoryId(domainHistoryId)
.build();
}
@@ -625,7 +624,7 @@ public final class DomainCreateFlow implements TransactionalFlow {
.setEventTime(createBillingEvent.getEventTime())
.setBillingTime(createBillingEvent.getBillingTime())
.setFlags(createBillingEvent.getFlags())
.setParent(createBillingEvent.getParentKey())
.setDomainHistoryId(createBillingEvent.getDomainHistoryId())
.build();
}
@@ -646,13 +645,12 @@ public final class DomainCreateFlow implements TransactionalFlow {
.build();
}
private void enqueueTasks(
DomainBase newDomain, boolean hasSignedMarks, boolean hasClaimsNotice) {
private void enqueueTasks(Domain newDomain, boolean hasSignedMarks, boolean hasClaimsNotice) {
if (newDomain.shouldPublishToDns()) {
dnsQueue.addDomainRefreshTask(newDomain.getDomainName());
}
if (hasClaimsNotice || hasSignedMarks) {
LordnTaskUtils.enqueueDomainBaseTask(newDomain);
LordnTaskUtils.enqueueDomainTask(newDomain);
}
}
@@ -64,7 +64,7 @@ import google.registry.flows.custom.DomainDeleteFlowCustomLogic.BeforeSaveParame
import google.registry.flows.custom.EntityChanges;
import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingEvent;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.domain.GracePeriod;
@@ -146,13 +146,13 @@ public final class DomainDeleteFlow implements TransactionalFlow {
extensionManager.validate();
DateTime now = tm().getTransactionTime();
// Loads the target resource if it exists
DomainBase existingDomain = loadAndVerifyExistence(DomainBase.class, targetId, now);
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
Registry registry = Registry.get(existingDomain.getTld());
verifyDeleteAllowed(existingDomain, registry, now);
flowCustomLogic.afterValidation(
AfterValidationParameters.newBuilder().setExistingDomain(existingDomain).build());
ImmutableSet.Builder<ImmutableObject> entitiesToSave = new ImmutableSet.Builder<>();
DomainBase.Builder builder;
Domain.Builder builder;
if (existingDomain.getStatusValues().contains(StatusValue.PENDING_TRANSFER)) {
builder =
denyPendingTransfer(existingDomain, TransferStatus.SERVER_CANCELLED, now, registrarId)
@@ -233,7 +233,12 @@ public final class DomainDeleteFlow implements TransactionalFlow {
// No cancellation is written if the grace period was not for a billable event.
if (gracePeriod.hasBillingEvent()) {
entitiesToSave.add(
BillingEvent.Cancellation.forGracePeriod(gracePeriod, now, domainHistoryKey, targetId));
BillingEvent.Cancellation.forGracePeriod(
gracePeriod,
now,
new DomainHistoryId(
domainHistoryKey.getParent().getName(), domainHistoryKey.getId()),
targetId));
if (gracePeriod.getOneTimeBillingEvent() != null) {
// Take the amount of amount of registration time being refunded off the expiration time.
// This can be either add grace periods or renew grace periods.
@@ -248,7 +253,7 @@ public final class DomainDeleteFlow implements TransactionalFlow {
}
builder.setRegistrationExpirationTime(newExpirationTime);
DomainBase newDomain = builder.build();
Domain newDomain = builder.build();
DomainHistory domainHistory =
buildDomainHistory(newDomain, registry, now, durationUntilDelete, inAddGracePeriod);
updateForeignKeyIndexDeletionTime(newDomain);
@@ -289,7 +294,7 @@ public final class DomainDeleteFlow implements TransactionalFlow {
.build();
}
private void verifyDeleteAllowed(DomainBase existingDomain, Registry registry, DateTime now)
private void verifyDeleteAllowed(Domain existingDomain, Registry registry, DateTime now)
throws EppException {
verifyNoDisallowedStatuses(existingDomain, DISALLOWED_STATUSES);
verifyOptionalAuthInfo(authInfo, existingDomain);
@@ -304,7 +309,7 @@ public final class DomainDeleteFlow implements TransactionalFlow {
}
private DomainHistory buildDomainHistory(
DomainBase domain,
Domain domain,
Registry registry,
DateTime now,
Duration durationUntilDelete,
@@ -337,7 +342,7 @@ public final class DomainDeleteFlow implements TransactionalFlow {
}
private PollMessage.OneTime createDeletePollMessage(
DomainBase existingDomain, Key<DomainHistory> domainHistoryKey, DateTime deletionTime) {
Domain existingDomain, Key<DomainHistory> domainHistoryKey, DateTime deletionTime) {
Optional<MetadataExtension> metadataExtension =
eppInput.getSingleExtension(MetadataExtension.class);
boolean hasMetadataMessage =
@@ -362,7 +367,7 @@ public final class DomainDeleteFlow implements TransactionalFlow {
}
private PollMessage.OneTime createImmediateDeletePollMessage(
DomainBase existingDomain,
Domain existingDomain,
Key<DomainHistory> domainHistoryKey,
DateTime now,
DateTime deletionTime) {
@@ -384,7 +389,7 @@ public final class DomainDeleteFlow implements TransactionalFlow {
@Nullable
private ImmutableList<FeeTransformResponseExtension> getResponseExtensions(
BillingEvent.Recurring recurringBillingEvent, DomainBase existingDomain, DateTime now) {
BillingEvent.Recurring recurringBillingEvent, Domain existingDomain, DateTime now) {
FeeTransformResponseExtension.Builder feeResponseBuilder = getDeleteResponseBuilder();
if (feeResponseBuilder == null) {
return ImmutableList.of();
@@ -25,7 +25,7 @@ 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.domain.DomainBase.MAX_REGISTRATION_YEARS;
import static google.registry.model.domain.Domain.MAX_REGISTRATION_YEARS;
import static google.registry.model.tld.Registries.findTldForName;
import static google.registry.model.tld.Registries.getTlds;
import static google.registry.model.tld.Registry.TldState.GENERAL_AVAILABILITY;
@@ -82,7 +82,7 @@ import google.registry.model.billing.BillingEvent.Recurring;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DesignatedContact;
import google.registry.model.domain.DesignatedContact.Type;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainCommand.Create;
import google.registry.model.domain.DomainCommand.CreateOrUpdate;
import google.registry.model.domain.DomainCommand.InvalidReferencesException;
@@ -553,7 +553,7 @@ public class DomainFlowUtils {
* Fills in a builder with the data needed for an autorenew billing event for this domain. This
* does not copy over the id of the current autorenew billing event.
*/
public static BillingEvent.Recurring.Builder newAutorenewBillingEvent(DomainBase domain) {
public static BillingEvent.Recurring.Builder newAutorenewBillingEvent(Domain domain) {
return new BillingEvent.Recurring.Builder()
.setReason(Reason.RENEW)
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
@@ -566,7 +566,7 @@ public class DomainFlowUtils {
* Fills in a builder with the data needed for an autorenew poll message for this domain. This
* does not copy over the id of the current autorenew poll message.
*/
public static PollMessage.Autorenew.Builder newAutorenewPollMessage(DomainBase domain) {
public static PollMessage.Autorenew.Builder newAutorenewPollMessage(Domain domain) {
return new PollMessage.Autorenew.Builder()
.setTargetId(domain.getDomainName())
.setRegistrarId(domain.getCurrentSponsorRegistrarId())
@@ -583,7 +583,7 @@ public class DomainFlowUtils {
*
* <p>Returns the new autorenew recurring billing event.
*/
public static Recurring updateAutorenewRecurrenceEndTime(DomainBase domain, DateTime newEndTime) {
public static Recurring updateAutorenewRecurrenceEndTime(Domain domain, DateTime newEndTime) {
Optional<PollMessage.Autorenew> autorenewPollMessage =
tm().loadByKeyIfPresent(domain.getAutorenewPollMessage());
@@ -628,7 +628,7 @@ public class DomainFlowUtils {
FeeQueryCommandExtensionItem feeRequest,
FeeQueryResponseExtensionItem.Builder<?, ?> builder,
InternetDomainName domainName,
Optional<DomainBase> domain,
Optional<Domain> domain,
@Nullable CurrencyUnit topLevelCurrency,
DateTime currentDate,
DomainPricingLogic pricingLogic,
@@ -878,7 +878,7 @@ public class DomainFlowUtils {
/**
* Check whether a new expiration time (via a renew) does not extend beyond a maximum number of
* years (e.g. {@link DomainBase#MAX_REGISTRATION_YEARS}) from "now".
* years (e.g. {@link Domain#MAX_REGISTRATION_YEARS}) from "now".
*
* @throws ExceedsMaxRegistrationYearsException if the new registration period is too long
*/
@@ -891,7 +891,7 @@ public class DomainFlowUtils {
/**
* Check that a new registration period (via a create) does not extend beyond a maximum number of
* years (e.g. {@link DomainBase#MAX_REGISTRATION_YEARS}).
* years (e.g. {@link Domain#MAX_REGISTRATION_YEARS}).
*
* @throws ExceedsMaxRegistrationYearsException if the new registration period is too long
*/
@@ -947,7 +947,7 @@ public class DomainFlowUtils {
}
/** If a domain "clientUpdateProhibited" set, updates must clear it or fail. */
static void verifyClientUpdateNotProhibited(Update command, DomainBase existingResource)
static void verifyClientUpdateNotProhibited(Update command, Domain existingResource)
throws ResourceHasClientUpdateProhibitedException {
if (existingResource.getStatusValues().contains(StatusValue.CLIENT_UPDATE_PROHIBITED)
&& !command
@@ -1120,13 +1120,13 @@ public class DomainFlowUtils {
* the most recent HistoryEntry that fits the above criteria, with negated reportAmounts.
*/
static ImmutableSet<DomainTransactionRecord> createCancelingRecords(
DomainBase domainBase,
Domain domain,
final DateTime now,
Duration maxSearchPeriod,
final ImmutableSet<TransactionReportField> cancelableFields) {
List<? extends HistoryEntry> recentHistoryEntries =
findRecentHistoryEntries(domainBase, now, maxSearchPeriod);
findRecentHistoryEntries(domain, now, maxSearchPeriod);
Optional<? extends HistoryEntry> entryToCancel =
Streams.findLast(
recentHistoryEntries.stream()
@@ -1165,14 +1165,14 @@ public class DomainFlowUtils {
}
private static List<? extends HistoryEntry> findRecentHistoryEntries(
DomainBase domainBase, DateTime now, Duration maxSearchPeriod) {
Domain domain, DateTime now, Duration maxSearchPeriod) {
return jpaTm()
.query(
"FROM DomainHistory WHERE modificationTime >= :beginning AND domainRepoId = "
+ ":repoId ORDER BY modificationTime ASC",
DomainHistory.class)
.setParameter("beginning", now.minus(maxSearchPeriod))
.setParameter("repoId", domainBase.getRepoId())
.setParameter("repoId", domain.getRepoId())
.getResultList();
}
@@ -36,7 +36,7 @@ import google.registry.flows.custom.DomainInfoFlowCustomLogic;
import google.registry.flows.custom.DomainInfoFlowCustomLogic.AfterValidationParameters;
import google.registry.flows.custom.DomainInfoFlowCustomLogic.BeforeResponseParameters;
import google.registry.flows.custom.DomainInfoFlowCustomLogic.BeforeResponseReturnData;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainCommand.Info;
import google.registry.model.domain.DomainCommand.Info.HostsRequest;
import google.registry.model.domain.DomainInfoData;
@@ -96,8 +96,8 @@ public final class DomainInfoFlow implements Flow {
validateRegistrarIsLoggedIn(registrarId);
extensionManager.validate();
DateTime now = clock.nowUtc();
DomainBase domain = verifyExistence(
DomainBase.class, targetId, loadByForeignKey(DomainBase.class, targetId, now));
Domain domain =
verifyExistence(Domain.class, targetId, loadByForeignKey(Domain.class, targetId, now));
verifyOptionalAuthInfo(authInfo, domain);
flowCustomLogic.afterValidation(
AfterValidationParameters.newBuilder().setDomain(domain).build());
@@ -142,8 +142,8 @@ public final class DomainInfoFlow implements Flow {
.build();
}
private ImmutableList<ResponseExtension> getDomainResponseExtensions(
DomainBase domain, DateTime now) throws EppException {
private ImmutableList<ResponseExtension> getDomainResponseExtensions(Domain domain, DateTime now)
throws EppException {
ImmutableList.Builder<ResponseExtension> extensions = new ImmutableList.Builder<>();
addSecDnsExtensionIfPresent(extensions, domain.getDsData());
ImmutableSet<GracePeriodStatus> gracePeriodStatuses = domain.getGracePeriodStatuses();
@@ -57,7 +57,7 @@ import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.OneTime;
import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.billing.BillingEvent.Recurring;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainCommand.Renew;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
@@ -166,7 +166,7 @@ public final class DomainRenewFlow implements TransactionalFlow {
DateTime now = tm().getTransactionTime();
Renew command = (Renew) resourceCommand;
// Loads the target resource if it exists
DomainBase existingDomain = loadAndVerifyExistence(DomainBase.class, targetId, now);
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
Optional<AllocationToken> allocationToken =
allocationTokenFlowUtils.verifyAllocationTokenIfPresent(
existingDomain,
@@ -210,7 +210,9 @@ public final class DomainRenewFlow implements TransactionalFlow {
.setEventTime(newExpirationTime)
.setRenewalPrice(existingRecurringBillingEvent.getRenewalPrice().orElse(null))
.setRenewalPriceBehavior(existingRecurringBillingEvent.getRenewalPriceBehavior())
.setParent(domainHistoryKey)
.setDomainHistoryId(
new DomainHistoryId(
domainHistoryKey.getParent().getName(), domainHistoryKey.getId()))
.build();
PollMessage.Autorenew newAutorenewPollMessage =
newAutorenewPollMessage(existingDomain)
@@ -221,7 +223,7 @@ public final class DomainRenewFlow implements TransactionalFlow {
.build();
// End the old autorenew billing event and poll message now. This may delete the poll message.
updateAutorenewRecurrenceEndTime(existingDomain, now);
DomainBase newDomain =
Domain newDomain =
existingDomain
.asBuilder()
.setLastEppUpdateTime(now)
@@ -273,7 +275,7 @@ public final class DomainRenewFlow implements TransactionalFlow {
}
private DomainHistory buildDomainHistory(
DomainBase newDomain, DateTime now, Period period, Duration renewGracePeriod) {
Domain newDomain, DateTime now, Period period, Duration renewGracePeriod) {
Optional<MetadataExtension> metadataExtensionOpt =
eppInput.getSingleExtension(MetadataExtension.class);
if (metadataExtensionOpt.isPresent()) {
@@ -297,10 +299,8 @@ public final class DomainRenewFlow implements TransactionalFlow {
.build();
}
private void verifyRenewAllowed(
Optional<AuthInfo> authInfo,
DomainBase existingDomain,
Renew command) throws EppException {
private void verifyRenewAllowed(Optional<AuthInfo> authInfo, Domain existingDomain, Renew command)
throws EppException {
verifyOptionalAuthInfo(authInfo, existingDomain);
verifyNoDisallowedStatuses(existingDomain, RENEW_DISALLOWED_STATUSES);
if (!isSuperuser) {
@@ -332,7 +332,8 @@ public final class DomainRenewFlow implements TransactionalFlow {
.setEventTime(now)
.setAllocationToken(allocationToken.map(AllocationToken::createVKey).orElse(null))
.setBillingTime(now.plus(Registry.get(tld).getRenewGracePeriodLength()))
.setParent(domainHistoryKey)
.setDomainHistoryId(
new DomainHistoryId(domainHistoryKey.getParent().getName(), domainHistoryKey.getId()))
.build();
}
@@ -50,7 +50,7 @@ import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.OneTime;
import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainCommand.Update;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
@@ -140,7 +140,7 @@ public final class DomainRestoreRequestFlow implements TransactionalFlow {
extensionManager.validate();
Update command = (Update) resourceCommand;
DateTime now = tm().getTransactionTime();
DomainBase existingDomain = loadAndVerifyExistence(DomainBase.class, targetId, now);
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
boolean isExpired = existingDomain.getRegistrationExpirationTime().isBefore(now);
FeesAndCredits feesAndCredits =
pricingLogic.getRestorePrice(
@@ -150,6 +150,8 @@ public final class DomainRestoreRequestFlow implements TransactionalFlow {
verifyRestoreAllowed(command, existingDomain, feeUpdate, feesAndCredits, now);
Key<DomainHistory> domainHistoryKey = createHistoryKey(existingDomain, DomainHistory.class);
historyBuilder.setId(domainHistoryKey.getId());
DomainHistoryId domainHistoryId =
new DomainHistoryId(domainHistoryKey.getParent().getName(), domainHistoryKey.getId());
ImmutableSet.Builder<ImmutableObject> entitiesToSave = new ImmutableSet.Builder<>();
DateTime newExpirationTime =
@@ -158,17 +160,17 @@ public final class DomainRestoreRequestFlow implements TransactionalFlow {
// a year and bill for it immediately, with no grace period.
if (isExpired) {
entitiesToSave.add(
createRenewBillingEvent(domainHistoryKey, feesAndCredits.getRenewCost(), now));
createRenewBillingEvent(domainHistoryId, feesAndCredits.getRenewCost(), now));
}
// Always bill for the restore itself.
entitiesToSave.add(
createRestoreBillingEvent(domainHistoryKey, feesAndCredits.getRestoreCost(), now));
createRestoreBillingEvent(domainHistoryId, feesAndCredits.getRestoreCost(), now));
BillingEvent.Recurring autorenewEvent =
newAutorenewBillingEvent(existingDomain)
.setEventTime(newExpirationTime)
.setRecurrenceEndTime(END_OF_TIME)
.setParent(domainHistoryKey)
.setDomainHistoryId(domainHistoryId)
.build();
PollMessage.Autorenew autorenewPollMessage =
newAutorenewPollMessage(existingDomain)
@@ -178,7 +180,7 @@ public final class DomainRestoreRequestFlow implements TransactionalFlow {
new DomainHistoryId(
domainHistoryKey.getParent().getName(), domainHistoryKey.getId()))
.build();
DomainBase newDomain =
Domain newDomain =
performRestore(
existingDomain,
newExpirationTime,
@@ -197,7 +199,7 @@ public final class DomainRestoreRequestFlow implements TransactionalFlow {
.build();
}
private DomainHistory buildDomainHistory(DomainBase newDomain, DateTime now) {
private DomainHistory buildDomainHistory(Domain newDomain, DateTime now) {
return historyBuilder
.setType(DOMAIN_RESTORE)
.setDomain(newDomain)
@@ -210,10 +212,11 @@ public final class DomainRestoreRequestFlow implements TransactionalFlow {
private void verifyRestoreAllowed(
Update command,
DomainBase existingDomain,
Domain existingDomain,
Optional<FeeUpdateCommandExtension> feeUpdate,
FeesAndCredits feesAndCredits,
DateTime now) throws EppException {
DateTime now)
throws EppException {
verifyOptionalAuthInfo(authInfo, existingDomain);
if (!isSuperuser) {
verifyResourceOwnership(registrarId, existingDomain);
@@ -233,8 +236,8 @@ public final class DomainRestoreRequestFlow implements TransactionalFlow {
validateFeeChallenge(targetId, now, feeUpdate, feesAndCredits);
}
private static DomainBase performRestore(
DomainBase existingDomain,
private static Domain performRestore(
Domain existingDomain,
DateTime newExpirationTime,
BillingEvent.Recurring autorenewEvent,
PollMessage.Autorenew autorenewPollMessage,
@@ -259,19 +262,17 @@ public final class DomainRestoreRequestFlow implements TransactionalFlow {
}
private OneTime createRenewBillingEvent(
Key<DomainHistory> domainHistoryKey, Money renewCost, DateTime now) {
return prepareBillingEvent(domainHistoryKey, renewCost, now).setReason(Reason.RENEW).build();
DomainHistoryId domainHistoryId, Money renewCost, DateTime now) {
return prepareBillingEvent(domainHistoryId, renewCost, now).setReason(Reason.RENEW).build();
}
private BillingEvent.OneTime createRestoreBillingEvent(
Key<DomainHistory> domainHistoryKey, Money restoreCost, DateTime now) {
return prepareBillingEvent(domainHistoryKey, restoreCost, now)
.setReason(Reason.RESTORE)
.build();
DomainHistoryId domainHistoryId, Money restoreCost, DateTime now) {
return prepareBillingEvent(domainHistoryId, restoreCost, now).setReason(Reason.RESTORE).build();
}
private OneTime.Builder prepareBillingEvent(
Key<DomainHistory> domainHistoryKey, Money cost, DateTime now) {
DomainHistoryId domainHistoryId, Money cost, DateTime now) {
return new BillingEvent.OneTime.Builder()
.setTargetId(targetId)
.setRegistrarId(registrarId)
@@ -279,7 +280,7 @@ public final class DomainRestoreRequestFlow implements TransactionalFlow {
.setBillingTime(now)
.setPeriodYears(1)
.setCost(cost)
.setParent(domainHistoryKey);
.setDomainHistoryId(domainHistoryId);
}
private static ImmutableList<FeeTransformResponseExtension> createResponseExtensions(
@@ -49,7 +49,7 @@ import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Flag;
import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.domain.GracePeriod;
@@ -100,7 +100,7 @@ public final class DomainTransferApproveFlow implements TransactionalFlow {
/**
* The logic in this flow, which handles client approvals, very closely parallels the logic in
* {@link DomainBase#cloneProjectedAtTime} which handles implicit server approvals.
* {@link Domain#cloneProjectedAtTime} which handles implicit server approvals.
*/
@Override
public EppResponse run() throws EppException {
@@ -108,7 +108,7 @@ public final class DomainTransferApproveFlow implements TransactionalFlow {
validateRegistrarIsLoggedIn(registrarId);
extensionManager.validate();
DateTime now = tm().getTransactionTime();
DomainBase existingDomain = loadAndVerifyExistence(DomainBase.class, targetId, now);
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
verifyOptionalAuthInfo(authInfo, existingDomain);
verifyHasPendingTransfer(existingDomain);
verifyResourceOwnership(registrarId, existingDomain);
@@ -123,7 +123,7 @@ public final class DomainTransferApproveFlow implements TransactionalFlow {
Key<DomainHistory> domainHistoryKey = createHistoryKey(existingDomain, DomainHistory.class);
historyBuilder.setId(domainHistoryKey.getId());
Optional<BillingEvent.OneTime> billingEvent =
(transferData.getTransferPeriod().getValue() == 0)
transferData.getTransferPeriod().getValue() == 0
? Optional.empty()
: Optional.of(
new BillingEvent.OneTime.Builder()
@@ -134,7 +134,9 @@ public final class DomainTransferApproveFlow implements TransactionalFlow {
.setCost(getDomainRenewCost(targetId, transferData.getTransferRequestTime(), 1))
.setEventTime(now)
.setBillingTime(now.plus(Registry.get(tld).getTransferGracePeriodLength()))
.setParent(domainHistoryKey)
.setDomainHistoryId(
new DomainHistoryId(
domainHistoryKey.getParent().getName(), domainHistoryKey.getId()))
.build());
ImmutableList.Builder<ImmutableObject> entitiesToSave = new ImmutableList.Builder<>();
// If we are within an autorenew grace period, cancel the autorenew billing event and don't
@@ -150,7 +152,11 @@ public final class DomainTransferApproveFlow implements TransactionalFlow {
if (billingEvent.isPresent()) {
entitiesToSave.add(
BillingEvent.Cancellation.forGracePeriod(
autorenewGrace, now, domainHistoryKey, targetId));
autorenewGrace,
now,
new DomainHistoryId(
domainHistoryKey.getParent().getName(), domainHistoryKey.getId()),
targetId));
}
}
// Close the old autorenew event and poll message at the transfer time (aka now). This may end
@@ -167,7 +173,9 @@ public final class DomainTransferApproveFlow implements TransactionalFlow {
.setRegistrarId(gainingRegistrarId)
.setEventTime(newExpirationTime)
.setRecurrenceEndTime(END_OF_TIME)
.setParent(domainHistoryKey)
.setDomainHistoryId(
new DomainHistoryId(
domainHistoryKey.getParent().getName(), domainHistoryKey.getId()))
.build();
// Create a new autorenew poll message.
PollMessage.Autorenew gainingClientAutorenewPollMessage =
@@ -182,9 +190,9 @@ public final class DomainTransferApproveFlow implements TransactionalFlow {
domainHistoryKey.getParent().getName(), domainHistoryKey.getId()))
.build();
// Construct the post-transfer domain.
DomainBase partiallyApprovedDomain =
Domain partiallyApprovedDomain =
approvePendingTransfer(existingDomain, TransferStatus.CLIENT_APPROVED, now);
DomainBase newDomain =
Domain newDomain =
partiallyApprovedDomain
.asBuilder()
// Update the transferredRegistrationExpirationTime here since approvePendingTransfer()
@@ -238,7 +246,7 @@ public final class DomainTransferApproveFlow implements TransactionalFlow {
}
private DomainHistory buildDomainHistory(
DomainBase newDomain, Registry registry, DateTime now, String gainingRegistrarId) {
Domain newDomain, Registry registry, DateTime now, String gainingRegistrarId) {
ImmutableSet<DomainTransactionRecord> cancelingRecords =
createCancelingRecords(
newDomain,
@@ -40,7 +40,7 @@ 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.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppcommon.AuthInfo;
@@ -90,7 +90,7 @@ public final class DomainTransferCancelFlow implements TransactionalFlow {
validateRegistrarIsLoggedIn(registrarId);
extensionManager.validate();
DateTime now = tm().getTransactionTime();
DomainBase existingDomain = loadAndVerifyExistence(DomainBase.class, targetId, now);
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
verifyOptionalAuthInfo(authInfo, existingDomain);
verifyHasPendingTransfer(existingDomain);
verifyTransferInitiator(registrarId, existingDomain);
@@ -104,7 +104,7 @@ public final class DomainTransferCancelFlow implements TransactionalFlow {
.setId(domainHistoryKey.getId())
.setOtherRegistrarId(existingDomain.getTransferData().getLosingRegistrarId());
DomainBase newDomain =
Domain newDomain =
denyPendingTransfer(existingDomain, TransferStatus.CLIENT_CANCELLED, now, registrarId);
DomainHistory domainHistory = buildDomainHistory(newDomain, registry, now);
tm().putAll(
@@ -123,7 +123,7 @@ public final class DomainTransferCancelFlow implements TransactionalFlow {
.build();
}
private DomainHistory buildDomainHistory(DomainBase newDomain, Registry registry, DateTime now) {
private DomainHistory buildDomainHistory(Domain newDomain, Registry registry, DateTime now) {
ImmutableSet<DomainTransactionRecord> cancelingRecords =
createCancelingRecords(
newDomain,
@@ -28,7 +28,7 @@ import google.registry.flows.ResourceFlowUtils;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.flows.exceptions.NoTransferHistoryToQueryException;
import google.registry.flows.exceptions.NotAuthorizedToViewTransferException;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppoutput.EppResponse;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
@@ -71,7 +71,7 @@ public final class DomainTransferQueryFlow implements Flow {
validateRegistrarIsLoggedIn(registrarId);
extensionManager.validate(); // There are no legal extensions for this flow.
DateTime now = clock.nowUtc();
DomainBase domain = loadAndVerifyExistence(DomainBase.class, targetId, now);
Domain domain = loadAndVerifyExistence(Domain.class, targetId, now);
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).
@@ -42,7 +42,7 @@ 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.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppcommon.AuthInfo;
@@ -92,7 +92,7 @@ public final class DomainTransferRejectFlow implements TransactionalFlow {
validateRegistrarIsLoggedIn(registrarId);
extensionManager.validate();
DateTime now = tm().getTransactionTime();
DomainBase existingDomain = loadAndVerifyExistence(DomainBase.class, targetId, now);
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
Registry registry = Registry.get(existingDomain.getTld());
Key<DomainHistory> domainHistoryKey = createHistoryKey(existingDomain, DomainHistory.class);
historyBuilder
@@ -105,7 +105,7 @@ public final class DomainTransferRejectFlow implements TransactionalFlow {
if (!isSuperuser) {
checkAllowedAccessToTld(registrarId, existingDomain.getTld());
}
DomainBase newDomain =
Domain newDomain =
denyPendingTransfer(existingDomain, TransferStatus.CLIENT_REJECTED, now, registrarId);
DomainHistory domainHistory = buildDomainHistory(newDomain, registry, now);
tm().putAll(
@@ -124,7 +124,7 @@ public final class DomainTransferRejectFlow implements TransactionalFlow {
.build();
}
private DomainHistory buildDomainHistory(DomainBase newDomain, Registry registry, DateTime now) {
private DomainHistory buildDomainHistory(Domain newDomain, Registry registry, DateTime now) {
ImmutableSet<DomainTransactionRecord> cancelingRecords =
createCancelingRecords(
newDomain,
@@ -52,7 +52,7 @@ import google.registry.flows.exceptions.InvalidTransferPeriodValueException;
import google.registry.flows.exceptions.ObjectAlreadySponsoredException;
import google.registry.flows.exceptions.TransferPeriodMustBeOneYearException;
import google.registry.flows.exceptions.TransferPeriodZeroAndFeeTransferExtensionException;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainCommand.Transfer;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.Period;
@@ -149,7 +149,7 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
verifyRegistrarIsActive(gainingClientId);
extensionManager.validate();
DateTime now = tm().getTransactionTime();
DomainBase existingDomain = loadAndVerifyExistence(DomainBase.class, targetId, now);
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
Optional<DomainTransferRequestSuperuserExtension> superuserExtension =
eppInput.getSingleExtension(DomainTransferRequestSuperuserExtension.class);
Period period =
@@ -190,7 +190,7 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
//
// See b/19430703#comment17 and https://www.icann.org/news/advisory-2002-06-06-en for the
// policy documentation for transfers subsuming autorenews within the autorenew grace period.
DomainBase domainAtTransferTime = existingDomain.cloneProjectedAtTime(automaticTransferTime);
Domain domainAtTransferTime = existingDomain.cloneProjectedAtTime(automaticTransferTime);
// The new expiration time if there is a server approval.
DateTime serverApproveNewExpirationTime =
computeExDateForApprovalTime(domainAtTransferTime, automaticTransferTime, period);
@@ -231,7 +231,7 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
// cloneProjectedAtTime() will replace these old autorenew entities with the server approve ones
// that we've created in this flow and stored in pendingTransferData.
updateAutorenewRecurrenceEndTime(existingDomain, automaticTransferTime);
DomainBase newDomain =
Domain newDomain =
existingDomain
.asBuilder()
.setTransferData(pendingTransferData)
@@ -255,7 +255,7 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
}
private void verifyTransferAllowed(
DomainBase existingDomain,
Domain existingDomain,
Period period,
DateTime now,
Optional<DomainTransferRequestSuperuserExtension> superuserExtension)
@@ -320,7 +320,7 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
}
private DomainHistory buildDomainHistory(
DomainBase newDomain, Registry registry, DateTime now, Period period) {
Domain newDomain, Registry registry, DateTime now, Period period) {
return historyBuilder
.setType(DOMAIN_TRANSFER_REQUEST)
.setPeriod(period)
@@ -337,7 +337,7 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
}
private DomainTransferResponse createResponse(
Period period, DomainBase existingDomain, DomainBase newDomain, DateTime now) {
Period period, Domain existingDomain, Domain newDomain, DateTime now) {
// If the registration were approved this instant, this is what the new expiration would be,
// because we cap at 10 years from the moment of approval. This is different than the server
// approval new expiration time, which is capped at 10 years from the server approve time.
@@ -24,7 +24,7 @@ import com.googlecode.objectify.Key;
import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Flag;
import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.domain.GracePeriod;
@@ -109,7 +109,7 @@ public final class DomainTransferUtils {
DateTime automaticTransferTime,
DateTime serverApproveNewExpirationTime,
Key<DomainHistory> domainHistoryKey,
DomainBase existingDomain,
Domain existingDomain,
Trid trid,
String gainingRegistrarId,
Optional<Money> transferCost,
@@ -250,7 +250,8 @@ public final class DomainTransferUtils {
.setRegistrarId(gainingRegistrarId)
.setEventTime(serverApproveNewExpirationTime)
.setRecurrenceEndTime(END_OF_TIME)
.setParent(domainHistoryKey)
.setDomainHistoryId(
new DomainHistoryId(domainHistoryKey.getParent().getName(), domainHistoryKey.getId()))
.build();
}
@@ -275,17 +276,20 @@ public final class DomainTransferUtils {
DateTime now,
Key<DomainHistory> domainHistoryKey,
String targetId,
DomainBase existingDomain,
Domain existingDomain,
Optional<Money> transferCost) {
DomainBase domainAtTransferTime =
existingDomain.cloneProjectedAtTime(automaticTransferTime);
Domain domainAtTransferTime = existingDomain.cloneProjectedAtTime(automaticTransferTime);
GracePeriod autorenewGracePeriod =
getOnlyElement(
domainAtTransferTime.getGracePeriodsOfType(GracePeriodStatus.AUTO_RENEW), null);
if (autorenewGracePeriod != null && transferCost.isPresent()) {
return Optional.of(
BillingEvent.Cancellation.forGracePeriod(
autorenewGracePeriod, now, domainHistoryKey, targetId)
autorenewGracePeriod,
now,
new DomainHistoryId(
domainHistoryKey.getParent().getName(), domainHistoryKey.getId()),
targetId)
.asBuilder()
.setEventTime(automaticTransferTime)
.build());
@@ -308,7 +312,8 @@ public final class DomainTransferUtils {
.setPeriodYears(1)
.setEventTime(automaticTransferTime)
.setBillingTime(automaticTransferTime.plus(registry.getTransferGracePeriodLength()))
.setParent(domainHistoryKey)
.setDomainHistoryId(
new DomainHistoryId(domainHistoryKey.getParent().getName(), domainHistoryKey.getId()))
.build();
}
@@ -67,7 +67,7 @@ import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.domain.DesignatedContact;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainCommand.Update;
import google.registry.model.domain.DomainCommand.Update.AddRemove;
import google.registry.model.domain.DomainCommand.Update.Change;
@@ -173,11 +173,11 @@ public final class DomainUpdateFlow implements TransactionalFlow {
extensionManager.validate();
DateTime now = tm().getTransactionTime();
Update command = cloneAndLinkReferences((Update) resourceCommand, now);
DomainBase existingDomain = loadAndVerifyExistence(DomainBase.class, targetId, now);
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
verifyUpdateAllowed(command, existingDomain, now);
flowCustomLogic.afterValidation(
AfterValidationParameters.newBuilder().setExistingDomain(existingDomain).build());
DomainBase newDomain = performUpdate(command, existingDomain, now);
Domain newDomain = performUpdate(command, existingDomain, now);
DomainHistory domainHistory =
historyBuilder.setType(DOMAIN_UPDATE).setDomain(newDomain).build();
validateNewState(newDomain);
@@ -204,7 +204,7 @@ public final class DomainUpdateFlow implements TransactionalFlow {
}
/** Fail if the object doesn't exist or was deleted. */
private void verifyUpdateAllowed(Update command, DomainBase existingDomain, DateTime now)
private void verifyUpdateAllowed(Update command, Domain existingDomain, DateTime now)
throws EppException {
verifyOptionalAuthInfo(authInfo, existingDomain);
AddRemove add = command.getInnerAdd();
@@ -233,8 +233,7 @@ public final class DomainUpdateFlow implements TransactionalFlow {
tld, add.getNameserverFullyQualifiedHostNames());
}
private DomainBase performUpdate(Update command, DomainBase domain, DateTime now)
throws EppException {
private Domain performUpdate(Update command, Domain domain, DateTime now) throws EppException {
AddRemove add = command.getInnerAdd();
AddRemove remove = command.getInnerRemove();
checkSameValuesNotAddedAndRemoved(add.getNameservers(), remove.getNameservers());
@@ -251,7 +250,7 @@ public final class DomainUpdateFlow implements TransactionalFlow {
Sets.union(Sets.difference(domain.getContacts(), remove.getContacts()), add.getContacts());
validateNoDuplicateContacts(newContacts);
DomainBase.Builder domainBuilder =
Domain.Builder domainBuilder =
domain
.asBuilder()
// Handle the secDNS extension. As dsData in secDnsUpdate is read from EPP input and
@@ -293,7 +292,7 @@ public final class DomainUpdateFlow implements TransactionalFlow {
}
}
private void validateNewState(DomainBase newDomain) throws EppException {
private void validateNewState(Domain newDomain) throws EppException {
validateRequiredContactsPresent(newDomain.getRegistrant(), newDomain.getContacts());
validateDsData(newDomain.getDsData());
validateNameserversCountForTld(
@@ -304,7 +303,7 @@ public final class DomainUpdateFlow implements TransactionalFlow {
/** Some status updates cost money. Bill only once no matter how many of them are changed. */
private Optional<BillingEvent.OneTime> createBillingEventForStatusUpdates(
DomainBase existingDomain, DomainBase newDomain, DomainHistory historyEntry, DateTime now) {
Domain existingDomain, Domain newDomain, DomainHistory historyEntry, DateTime now) {
Optional<MetadataExtension> metadataExtension =
eppInput.getSingleExtension(MetadataExtension.class);
if (metadataExtension.isPresent() && metadataExtension.get().getRequestedByRegistrar()) {
@@ -320,7 +319,7 @@ public final class DomainUpdateFlow implements TransactionalFlow {
.setCost(Registry.get(existingDomain.getTld()).getServerStatusChangeCost())
.setEventTime(now)
.setBillingTime(now)
.setParent(historyEntry)
.setDomainHistory(historyEntry)
.build());
}
}
@@ -330,7 +329,7 @@ public final class DomainUpdateFlow implements TransactionalFlow {
/** Enqueues a poll message iff a superuser is adding/removing server statuses. */
private Optional<PollMessage.OneTime> createPollMessageForServerStatusUpdates(
DomainBase existingDomain, DomainBase newDomain, DomainHistory historyEntry, DateTime now) {
Domain existingDomain, Domain newDomain, DomainHistory historyEntry, DateTime now) {
if (registrarId.equals(existingDomain.getPersistedCurrentSponsorRegistrarId())) {
// Don't send a poll message when a superuser registrar is updating its own domain.
return Optional.empty();
@@ -19,7 +19,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.net.InternetDomainName;
import google.registry.flows.EppException;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainCommand;
import google.registry.model.domain.token.AllocationToken;
import google.registry.model.tld.Registry;
@@ -46,7 +46,7 @@ public class AllocationTokenCustomLogic {
/** Performs additional custom logic for validating a token on an existing domain. */
public AllocationToken validateToken(
DomainBase domain, AllocationToken token, Registry registry, String registrarId, DateTime now)
Domain domain, AllocationToken token, Registry registry, String registrarId, DateTime now)
throws EppException {
// Do nothing.
return token;
@@ -26,7 +26,7 @@ import google.registry.flows.EppException;
import google.registry.flows.EppException.AssociationProhibitsOperationException;
import google.registry.flows.EppException.AuthorizationErrorException;
import google.registry.flows.EppException.StatusProhibitsOperationException;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainCommand;
import google.registry.model.domain.token.AllocationToken;
import google.registry.model.domain.token.AllocationToken.TokenStatus;
@@ -171,7 +171,7 @@ public class AllocationTokenFlowUtils {
/** Verifies and returns the allocation token if one is specified, otherwise does nothing. */
public Optional<AllocationToken> verifyAllocationTokenIfPresent(
DomainBase existingDomain,
Domain existingDomain,
Registry registry,
String registrarId,
DateTime now,
@@ -41,7 +41,7 @@ import google.registry.flows.annotations.ReportingSpec;
import google.registry.flows.exceptions.ResourceAlreadyExistsForThisClientException;
import google.registry.flows.exceptions.ResourceCreateContentionException;
import google.registry.model.ImmutableObject;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppoutput.CreateData.HostCreateData;
@@ -109,7 +109,7 @@ public final class HostCreateFlow implements TransactionalFlow {
// The superordinate domain of the host object if creating an in-bailiwick host, or null if
// creating an external host. This is looked up before we actually create the Host object so
// we can detect error conditions earlier.
Optional<DomainBase> superordinateDomain =
Optional<Domain> superordinateDomain =
lookupSuperordinateDomain(validateHostName(targetId), now);
verifySuperordinateDomainNotInPendingDelete(superordinateDomain.orElse(null));
verifySuperordinateDomainOwnership(registrarId, superordinateDomain.orElse(null));
@@ -128,7 +128,7 @@ public final class HostCreateFlow implements TransactionalFlow {
.setHostName(targetId)
.setInetAddresses(command.getInetAddresses())
.setRepoId(createRepoId(allocateId(), roidSuffix))
.setSuperordinateDomain(superordinateDomain.map(DomainBase::createVKey).orElse(null))
.setSuperordinateDomain(superordinateDomain.map(Domain::createVKey).orElse(null))
.build();
historyBuilder.setType(HOST_CREATE).setHost(newHost);
ImmutableSet<ImmutableObject> entitiesToSave =
@@ -29,7 +29,7 @@ import google.registry.flows.EppException.ParameterValuePolicyErrorException;
import google.registry.flows.EppException.ParameterValueRangeErrorException;
import google.registry.flows.EppException.ParameterValueSyntaxErrorException;
import google.registry.flows.EppException.StatusProhibitsOperationException;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.eppcommon.StatusValue;
import google.registry.util.Idn;
import java.util.Optional;
@@ -77,8 +77,8 @@ public class HostFlowUtils {
}
}
/** Return the {@link DomainBase} this host is subordinate to, or null for external hosts. */
public static Optional<DomainBase> lookupSuperordinateDomain(
/** Return the {@link Domain} this host is subordinate to, or null for external hosts. */
public static Optional<Domain> lookupSuperordinateDomain(
InternetDomainName hostName, DateTime now) throws EppException {
Optional<InternetDomainName> tld = findTldForName(hostName);
if (!tld.isPresent()) {
@@ -90,8 +90,7 @@ public class HostFlowUtils {
hostName.parts().stream()
.skip(hostName.parts().size() - (tld.get().parts().size() + 1))
.collect(joining("."));
Optional<DomainBase> superordinateDomain =
loadByForeignKey(DomainBase.class, domainName, now);
Optional<Domain> superordinateDomain = loadByForeignKey(Domain.class, domainName, now);
if (!superordinateDomain.isPresent() || !isActive(superordinateDomain.get(), now)) {
throw new SuperordinateDomainDoesNotExistException(domainName);
}
@@ -101,12 +100,12 @@ public class HostFlowUtils {
/** Superordinate domain for this hostname does not exist. */
static class SuperordinateDomainDoesNotExistException extends ObjectDoesNotExistException {
public SuperordinateDomainDoesNotExistException(String domainName) {
super(DomainBase.class, domainName);
super(Domain.class, domainName);
}
}
/** Ensure that the superordinate domain is sponsored by the provided registrar ID. */
static void verifySuperordinateDomainOwnership(String registrarId, DomainBase superordinateDomain)
static void verifySuperordinateDomainOwnership(String registrarId, Domain superordinateDomain)
throws EppException {
if (superordinateDomain != null
&& !registrarId.equals(superordinateDomain.getCurrentSponsorRegistrarId())) {
@@ -122,7 +121,7 @@ public class HostFlowUtils {
}
/** Ensure that the superordinate domain is not in pending delete. */
static void verifySuperordinateDomainNotInPendingDelete(DomainBase superordinateDomain)
static void verifySuperordinateDomainNotInPendingDelete(Domain superordinateDomain)
throws EppException {
if ((superordinateDomain != null)
&& superordinateDomain.getStatusValues().contains(StatusValue.PENDING_DELETE)) {
@@ -27,7 +27,7 @@ import google.registry.flows.Flow;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppoutput.EppResponse;
import google.registry.model.host.HostInfoData;
@@ -76,7 +76,7 @@ public final class HostInfoFlow implements Flow {
// the client id, last transfer time, and pending transfer status need to be read off of it. If
// there is no superordinate domain, the host's own values for these fields will be correct.
if (host.isSubordinate()) {
DomainBase superordinateDomain =
Domain superordinateDomain =
tm().transact(
() -> tm().loadByKey(host.getSuperordinateDomain()).cloneProjectedAtTime(now));
hostInfoDataBuilder
@@ -47,7 +47,7 @@ import google.registry.flows.annotations.ReportingSpec;
import google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException;
import google.registry.model.EppResource;
import google.registry.model.ImmutableObject;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppinput.ResourceCommand;
@@ -137,12 +137,12 @@ public final class HostUpdateFlow implements TransactionalFlow {
boolean isHostRename = suppliedNewHostName != null;
String oldHostName = targetId;
String newHostName = firstNonNull(suppliedNewHostName, oldHostName);
DomainBase oldSuperordinateDomain =
Domain oldSuperordinateDomain =
existingHost.isSubordinate()
? tm().loadByKey(existingHost.getSuperordinateDomain()).cloneProjectedAtTime(now)
: null;
// Note that lookupSuperordinateDomain calls cloneProjectedAtTime on the domain for us.
Optional<DomainBase> newSuperordinateDomain =
Optional<Domain> newSuperordinateDomain =
lookupSuperordinateDomain(validateHostName(newHostName), now);
verifySuperordinateDomainNotInPendingDelete(newSuperordinateDomain.orElse(null));
EppResource owningResource = firstNonNull(oldSuperordinateDomain, existingHost);
@@ -155,8 +155,8 @@ public final class HostUpdateFlow implements TransactionalFlow {
AddRemove remove = command.getInnerRemove();
checkSameValuesNotAddedAndRemoved(add.getStatusValues(), remove.getStatusValues());
checkSameValuesNotAddedAndRemoved(add.getInetAddresses(), remove.getInetAddresses());
VKey<DomainBase> newSuperordinateDomainKey =
newSuperordinateDomain.map(DomainBase::createVKey).orElse(null);
VKey<Domain> newSuperordinateDomainKey =
newSuperordinateDomain.map(Domain::createVKey).orElse(null);
// If the superordinateDomain field is changing, set the lastSuperordinateChange to now.
DateTime lastSuperordinateChange =
Objects.equals(newSuperordinateDomainKey, existingHost.getSuperordinateDomain())
@@ -211,10 +211,10 @@ public final class HostUpdateFlow implements TransactionalFlow {
private void verifyUpdateAllowed(
Update command,
HostResource existingHost,
DomainBase newSuperordinateDomain,
Domain newSuperordinateDomain,
EppResource owningResource,
boolean isHostRename)
throws EppException {
throws EppException {
if (!isSuperuser) {
// Verify that the host belongs to this registrar, either directly or because it is currently
// subordinate to a domain owned by this registrar.
@@ -20,6 +20,7 @@ import static google.registry.model.IdService.allocateId;
import static google.registry.model.ModelUtils.getAllFields;
import com.googlecode.objectify.annotation.Id;
import google.registry.model.annotations.OfyIdAllocation;
import google.registry.util.TypeUtils.TypeInstantiator;
import java.lang.reflect.Field;
import java.util.Optional;
@@ -59,7 +60,10 @@ public interface Buildable {
// any entity it has one and only one @Id field in its class hierarchy.
Field idField =
getAllFields(instance.getClass()).values().stream()
.filter(field -> field.isAnnotationPresent(Id.class))
.filter(
field ->
field.isAnnotationPresent(Id.class)
|| field.isAnnotationPresent(OfyIdAllocation.class))
.findFirst()
.orElse(null);
if (idField != null
@@ -16,12 +16,11 @@ package google.registry.model;
import com.google.common.collect.ImmutableSet;
import google.registry.model.annotations.DeleteAfterMigration;
import google.registry.model.billing.BillingEvent;
import google.registry.model.common.EntityGroupRoot;
import google.registry.model.common.GaeUserIdConverter;
import google.registry.model.contact.ContactHistory;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.token.AllocationToken;
import google.registry.model.host.HostHistory;
@@ -44,13 +43,9 @@ public final class EntityClasses {
public static final ImmutableSet<Class<? extends ImmutableObject>> ALL_CLASSES =
ImmutableSet.of(
AllocationToken.class,
BillingEvent.Cancellation.class,
BillingEvent.Modification.class,
BillingEvent.OneTime.class,
BillingEvent.Recurring.class,
ContactHistory.class,
ContactResource.class,
DomainBase.class,
Domain.class,
DomainHistory.class,
EntityGroupRoot.class,
EppResourceIndex.class,
@@ -33,7 +33,7 @@ import google.registry.model.EppResource.BuilderWithTransferData;
import google.registry.model.EppResource.ForeignKeyedEppResource;
import google.registry.model.EppResource.ResourceWithTransferData;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.HostResource;
import google.registry.model.index.ForeignKeyIndex;
@@ -342,7 +342,7 @@ public final class EppResourceUtils {
* @param now the logical time of the check
* @param limit the maximum number of returned keys, unlimited if null
*/
public static ImmutableSet<VKey<DomainBase>> getLinkedDomainKeys(
public static ImmutableSet<VKey<Domain>> getLinkedDomainKeys(
VKey<? extends EppResource> key, DateTime now, @Nullable Integer limit) {
checkArgument(
key.getKind().equals(ContactResource.class) || key.getKind().equals(HostResource.class),
@@ -350,16 +350,16 @@ public final class EppResourceUtils {
key);
boolean isContactKey = key.getKind().equals(ContactResource.class);
if (tm().isOfy()) {
com.googlecode.objectify.cmd.Query<DomainBase> query =
com.googlecode.objectify.cmd.Query<Domain> query =
auditedOfy()
.load()
.type(DomainBase.class)
.type(Domain.class)
.filter(isContactKey ? "allContacts.contact" : "nsHosts", key.getOfyKey())
.filter("deletionTime >", now);
if (limit != null) {
query.limit(limit);
}
return query.keys().list().stream().map(DomainBase::createVKey).collect(toImmutableSet());
return query.keys().list().stream().map(Domain::createVKey).collect(toImmutableSet());
} else {
return tm().transact(
() -> {
@@ -382,16 +382,15 @@ public final class EppResourceUtils {
query.setMaxResults(limit);
}
@SuppressWarnings("unchecked")
ImmutableSet<VKey<DomainBase>> domainBaseKeySet =
(ImmutableSet<VKey<DomainBase>>)
ImmutableSet<VKey<Domain>> domainKeySet =
(ImmutableSet<VKey<Domain>>)
query
.getResultStream()
.map(
repoId ->
DomainBase.createVKey(
Key.create(DomainBase.class, (String) repoId)))
Domain.createVKey(Key.create(Domain.class, (String) repoId)))
.collect(toImmutableSet());
return domainBaseKeySet;
return domainKeySet;
});
}
}
@@ -26,7 +26,7 @@ import google.registry.model.EppResource.BuilderWithTransferData;
import google.registry.model.EppResource.ForeignKeyedEppResource;
import google.registry.model.EppResource.ResourceWithTransferData;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppcommon.Trid;
import google.registry.model.index.ForeignKeyIndex;
@@ -101,7 +101,7 @@ public final class ResourceTransferUtils {
}
private static void assertIsContactOrDomain(EppResource eppResource) {
checkState(eppResource instanceof ContactResource || eppResource instanceof DomainBase);
checkState(eppResource instanceof ContactResource || eppResource instanceof Domain);
}
/** Update the relevant {@link ForeignKeyIndex} to cache the new deletion time. */
@@ -0,0 +1,36 @@
// 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.model.annotations;
import google.registry.model.IdService;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation to indicate an ID field that needs to be allocated by Ofy.
*
* <p>This annotation is only used for the field of a {@link google.registry.model.Buildable} class
* that was previously annotated by both Ofy's and JPA's {@code @Id} annotations, of which the Ofy
* annotation has been removed. The field still needs to be allocated automatically by the builder,
* via the {@link IdService#allocateId()}.
*
* <p>It should be removed after we switch to using SQL to directly allocate IDs.
*/
@DeleteAfterMigration
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface OfyIdAllocation {}
@@ -18,7 +18,6 @@ import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.CollectionUtils.forceEmptyToNull;
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
@@ -26,31 +25,21 @@ import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Ignore;
import com.googlecode.objectify.annotation.IgnoreSave;
import com.googlecode.objectify.annotation.Index;
import com.googlecode.objectify.annotation.Parent;
import com.googlecode.objectify.condition.IfNull;
import google.registry.model.Buildable;
import google.registry.model.ImmutableObject;
import google.registry.model.UnsafeSerializable;
import google.registry.model.annotations.OfyIdAllocation;
import google.registry.model.annotations.ReportedOn;
import google.registry.model.common.TimeOfYear;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.token.AllocationToken;
import google.registry.model.transfer.TransferData.TransferServerApproveEntity;
import google.registry.persistence.BillingVKey.BillingEventVKey;
import google.registry.persistence.BillingVKey.BillingRecurrenceVKey;
import google.registry.persistence.VKey;
import google.registry.persistence.WithLongVKey;
import google.registry.persistence.converter.JodaMoneyType;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nullable;
@@ -58,11 +47,13 @@ import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.MappedSuperclass;
import javax.persistence.PostLoad;
import javax.persistence.Transient;
import javax.persistence.Table;
import org.hibernate.annotations.Columns;
import org.hibernate.annotations.Type;
import org.joda.money.Money;
@@ -76,7 +67,7 @@ public abstract class BillingEvent extends ImmutableObject
/** The reason for the bill, which maps 1:1 to skus in go/registry-billing-skus. */
public enum Reason {
CREATE(true),
@Deprecated // TODO(b/31676071): remove this legacy value once old data is cleaned up.
@Deprecated // DO NOT USE THIS REASON. IT REMAINS BECAUSE OF HISTORICAL DATA. SEE b/31676071.
ERROR(false),
FEE_EARLY_ACCESS(true),
RENEW(true),
@@ -105,9 +96,7 @@ public abstract class BillingEvent extends ImmutableObject
ALLOCATION,
ANCHOR_TENANT,
AUTO_RENEW,
/**
* Landrush billing events are historical only and are no longer created.
*/
/** Landrush billing events are historical only and are no longer created. */
LANDRUSH,
/**
* This flag is used on create {@link OneTime} billing events for domains that were reserved.
@@ -122,7 +111,7 @@ public abstract class BillingEvent extends ImmutableObject
* This flag will be added to any {@link OneTime} events that are created via, e.g., an
* automated process to expand {@link Recurring} events.
*/
SYNTHETIC;
SYNTHETIC
}
/**
@@ -149,37 +138,30 @@ public abstract class BillingEvent extends ImmutableObject
*/
NONPREMIUM,
/**
* This indicates that the renewalPrice in {@link BillingEvent.Recurring} will be used for
* domain renewal.
* This indicates that the renewalPrice in {@link Recurring} will be used for domain renewal.
*
* <p>The renewalPrice has a non-null value iff the price behavior is set to "SPECIFIED". This
* behavior is used with internal registrations.
*/
SPECIFIED;
SPECIFIED
}
/** Entity id. */
@Id @javax.persistence.Id Long id;
@Parent @DoNotHydrate @Transient Key<DomainHistory> parent;
@OfyIdAllocation @Id Long id;
/** The registrar to bill. */
@Index
@Column(name = "registrarId", nullable = false)
String clientId;
/** Revision id of the entry in DomainHistory table that ths bill belongs to. */
@Ignore
@Column(nullable = false)
Long domainHistoryRevisionId;
/** ID of the EPP resource that the bill is for. */
@Ignore
@Column(nullable = false)
String domainRepoId;
/** When this event was created. For recurring events, this is also the recurrence start time. */
@Index
@Column(nullable = false)
DateTime eventTime;
@@ -192,17 +174,7 @@ public abstract class BillingEvent extends ImmutableObject
@Column(name = "domain_name", nullable = false)
String targetId;
@Nullable
Set<Flag> flags;
@PostLoad
void postLoad() {
parent =
Key.create(
Key.create(DomainBase.class, domainRepoId),
DomainHistory.class,
domainHistoryRevisionId);
}
@Nullable Set<Flag> flags;
public String getRegistrarId() {
return clientId;
@@ -232,8 +204,8 @@ public abstract class BillingEvent extends ImmutableObject
return targetId;
}
public Key<DomainHistory> getParentKey() {
return parent;
public DomainHistoryId getDomainHistoryId() {
return new DomainHistoryId(domainRepoId, domainHistoryRevisionId);
}
public ImmutableSet<Flag> getFlags() {
@@ -269,16 +241,6 @@ public abstract class BillingEvent extends ImmutableObject
return thisCastToDerived();
}
public B setDomainHistoryRevisionId(long domainHistoryRevisionId) {
getInstance().domainHistoryRevisionId = domainHistoryRevisionId;
return thisCastToDerived();
}
public B setDomainRepoId(String domainRepoId) {
getInstance().domainRepoId = domainRepoId;
return thisCastToDerived();
}
public B setEventTime(DateTime eventTime) {
getInstance().eventTime = eventTime;
return thisCastToDerived();
@@ -294,14 +256,14 @@ public abstract class BillingEvent extends ImmutableObject
return thisCastToDerived();
}
public B setParent(DomainHistory parent) {
getInstance().parent = Key.create(parent);
public B setDomainHistoryId(DomainHistoryId domainHistoryId) {
getInstance().domainHistoryRevisionId = domainHistoryId.getId();
getInstance().domainRepoId = domainHistoryId.getDomainRepoId();
return thisCastToDerived();
}
public B setParent(Key<DomainHistory> parentKey) {
getInstance().parent = parentKey;
return thisCastToDerived();
public B setDomainHistory(DomainHistory domainHistory) {
return setDomainHistoryId(domainHistory.getDomainHistoryId());
}
@Override
@@ -311,29 +273,23 @@ public abstract class BillingEvent extends ImmutableObject
checkNotNull(instance.clientId, "Registrar ID must be set");
checkNotNull(instance.eventTime, "Event time must be set");
checkNotNull(instance.targetId, "Target ID must be set");
checkNotNull(instance.parent, "Parent must be set");
checkNotNull(instance.parent.getParent(), "parent.getParent() must be set");
checkNotNull(
instance.parent.getParent().getName(), "parent.getParent().getName() must be set");
instance.domainHistoryRevisionId = instance.parent.getId();
instance.domainRepoId = instance.parent.getParent().getName();
checkNotNull(instance.domainHistoryRevisionId, "Domain History Revision ID must be set");
checkNotNull(instance.domainRepoId, "Domain Repo ID must be set");
return super.build();
}
}
/** A one-time billable event. */
@ReportedOn
@Entity
@javax.persistence.Entity(name = "BillingEvent")
@javax.persistence.Table(
@Entity(name = "BillingEvent")
@Table(
indexes = {
@javax.persistence.Index(columnList = "registrarId"),
@javax.persistence.Index(columnList = "eventTime"),
@javax.persistence.Index(columnList = "billingTime"),
@javax.persistence.Index(columnList = "syntheticCreationTime"),
@javax.persistence.Index(columnList = "domainRepoId"),
@javax.persistence.Index(columnList = "allocationToken"),
@javax.persistence.Index(columnList = "cancellation_matching_billing_recurrence_id")
@Index(columnList = "registrarId"),
@Index(columnList = "eventTime"),
@Index(columnList = "billingTime"),
@Index(columnList = "syntheticCreationTime"),
@Index(columnList = "domainRepoId"),
@Index(columnList = "allocationToken"),
@Index(columnList = "cancellation_matching_billing_recurrence_id")
})
@AttributeOverride(name = "id", column = @Column(name = "billing_event_id"))
@WithLongVKey(compositeKey = true)
@@ -345,15 +301,13 @@ public abstract class BillingEvent extends ImmutableObject
Money cost;
/** When the cost should be billed. */
@Index
DateTime billingTime;
/**
* The period in years of the action being billed for, if applicable, otherwise null. Used for
* financial reporting.
*/
@IgnoreSave(IfNull.class)
Integer periodYears = null;
Integer periodYears;
/**
* For {@link Flag#SYNTHETIC} events, when this event was persisted to Datastore (i.e. the
@@ -361,11 +315,10 @@ public abstract class BillingEvent extends ImmutableObject
* needs to be undone, a query on this field will return the complete set of potentially bad
* events.
*/
@Index
DateTime syntheticCreationTime;
/**
* For {@link Flag#SYNTHETIC} events, a {@link Key} to the {@link Recurring} from which this
* For {@link Flag#SYNTHETIC} events, a {@link VKey} to the {@link Recurring} from which this
* {@link OneTime} was created. This is needed in order to properly match billing events against
* {@link Cancellation}s.
*/
@@ -373,20 +326,17 @@ public abstract class BillingEvent extends ImmutableObject
VKey<Recurring> cancellationMatchingBillingEvent;
/**
* For {@link Flag#SYNTHETIC} events, the {@link DomainHistory} revision ID of the the {@link
* For {@link Flag#SYNTHETIC} events, the {@link DomainHistory} revision ID of the {@link
* Recurring} from which this {@link OneTime} was created. This is needed in order to recreate
* the {@link VKey} when reading from SQL.
*/
@Ignore
@Column(name = "recurrence_history_revision_id")
Long recurringEventHistoryRevisionId;
/**
* The {@link AllocationToken} used in the creation of this event, or null if one was not used.
*/
@Index
@Nullable
VKey<AllocationToken> allocationToken;
@Nullable VKey<AllocationToken> allocationToken;
public Money getCost() {
return cost;
@@ -418,11 +368,11 @@ public abstract class BillingEvent extends ImmutableObject
@Override
public VKey<OneTime> createVKey() {
return VKey.create(OneTime.class, getId(), Key.create(this));
return createVKey(getId());
}
public static VKey<OneTime> createVKey(Key<OneTime> key) {
return VKey.create(OneTime.class, key.getId(), key);
public static VKey<OneTime> createVKey(long id) {
return VKey.createSql(OneTime.class, id);
}
@Override
@@ -430,19 +380,6 @@ public abstract class BillingEvent extends ImmutableObject
return new Builder(clone(this));
}
@Override
void postLoad() {
super.postLoad();
if (cancellationMatchingBillingEvent != null) {
cancellationMatchingBillingEvent =
cancellationMatchingBillingEvent.restoreOfy(
DomainBase.class,
domainRepoId,
DomainHistory.class,
recurringEventHistoryRevisionId);
}
}
/** A builder for {@link OneTime} since it is immutable. */
public static class Builder extends BillingEvent.Builder<OneTime, Builder> {
@@ -475,11 +412,11 @@ public abstract class BillingEvent extends ImmutableObject
}
public Builder setCancellationMatchingBillingEvent(
VKey<Recurring> cancellationMatchingBillingEvent) {
getInstance().cancellationMatchingBillingEvent = cancellationMatchingBillingEvent;
// getOfyKey() here is safe, recurring billing event VKeys have a valid ofy key.
Recurring cancellationMatchingBillingEvent) {
getInstance().cancellationMatchingBillingEvent =
cancellationMatchingBillingEvent.createVKey();
getInstance().recurringEventHistoryRevisionId =
cancellationMatchingBillingEvent.getOfyKey().getParent().getId();
cancellationMatchingBillingEvent.getDomainHistoryRevisionId();
return this;
}
@@ -511,12 +448,6 @@ public abstract class BillingEvent extends ImmutableObject
== (instance.cancellationMatchingBillingEvent != null),
"Cancellation matching billing event must be set if and only if the SYNTHETIC flag "
+ "is set.");
// getOfyKey() here is safe, billing event VKeys have a valid ofy key.
checkState(
!instance.getFlags().contains(Flag.SYNTHETIC)
|| (instance.cancellationMatchingBillingEvent.getOfyKey().getParent().getId()
== instance.recurringEventHistoryRevisionId),
"Cancellation matching billing event and its history revision ID does not match.");
return super.build();
}
}
@@ -526,29 +457,26 @@ public abstract class BillingEvent extends ImmutableObject
* A recurring billable event.
*
* <p>Unlike {@link OneTime} events, these do not store an explicit cost, since the cost of the
* recurring event might change and each time we bill for it we need to bill at the current cost,
* recurring event might change and each time we bill for it, we need to bill at the current cost,
* not the value that was in use at the time the recurrence was created.
*/
@ReportedOn
@Entity
@javax.persistence.Entity(name = "BillingRecurrence")
@javax.persistence.Table(
@Entity(name = "BillingRecurrence")
@Table(
indexes = {
@javax.persistence.Index(columnList = "registrarId"),
@javax.persistence.Index(columnList = "eventTime"),
@javax.persistence.Index(columnList = "domainRepoId"),
@javax.persistence.Index(columnList = "recurrenceEndTime"),
@javax.persistence.Index(columnList = "recurrence_time_of_year")
@Index(columnList = "registrarId"),
@Index(columnList = "eventTime"),
@Index(columnList = "domainRepoId"),
@Index(columnList = "recurrenceEndTime"),
@Index(columnList = "recurrence_time_of_year")
})
@AttributeOverride(name = "id", column = @Column(name = "billing_recurrence_id"))
@WithLongVKey(compositeKey = true)
public static class Recurring extends BillingEvent {
/**
* The billing event recurs every year between {@link #eventTime} and this time on the
* [month, day, time] specified in {@link #recurrenceTimeOfYear}.
* The billing event recurs every year between {@link #eventTime} and this time on the [month,
* day, time] specified in {@link #recurrenceTimeOfYear}.
*/
@Index
DateTime recurrenceEndTime;
/**
@@ -564,11 +492,9 @@ public abstract class BillingEvent extends ImmutableObject
* (same day of year, which can be 365 or 366 days later) which is what {@link TimeOfYear} can
* model, whereas the billing time is a fixed {@link org.joda.time.Duration} later.
*/
@Index
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "timeString", column = @Column(name = "recurrence_time_of_year"))
})
@AttributeOverrides(
@AttributeOverride(name = "timeString", column = @Column(name = "recurrence_time_of_year")))
TimeOfYear recurrenceTimeOfYear;
/**
@@ -605,11 +531,11 @@ public abstract class BillingEvent extends ImmutableObject
@Override
public VKey<Recurring> createVKey() {
return VKey.create(Recurring.class, getId(), Key.create(this));
return createVKey(getId());
}
public static VKey<Recurring> createVKey(Key<Recurring> key) {
return VKey.create(Recurring.class, key.getId(), key);
public static VKey<Recurring> createVKey(Long id) {
return VKey.createSql(Recurring.class, id);
}
@Override
@@ -647,8 +573,8 @@ public abstract class BillingEvent extends ImmutableObject
checkNotNull(instance.eventTime);
checkNotNull(instance.reason);
checkArgument(
(instance.renewalPriceBehavior == RenewalPriceBehavior.SPECIFIED)
^ (instance.renewalPrice == null),
instance.renewalPriceBehavior == RenewalPriceBehavior.SPECIFIED
^ instance.renewalPrice == null,
"Renewal price can have a value if and only if the renewal price behavior is"
+ " SPECIFIED");
instance.recurrenceTimeOfYear = TimeOfYear.fromDateTime(instance.eventTime);
@@ -666,47 +592,45 @@ public abstract class BillingEvent extends ImmutableObject
* preserve the immutability of billing events.
*/
@ReportedOn
@Entity
@javax.persistence.Entity(name = "BillingCancellation")
@javax.persistence.Table(
@Entity(name = "BillingCancellation")
@Table(
indexes = {
@javax.persistence.Index(columnList = "registrarId"),
@javax.persistence.Index(columnList = "eventTime"),
@javax.persistence.Index(columnList = "domainRepoId"),
@javax.persistence.Index(columnList = "billingTime"),
@javax.persistence.Index(columnList = "billing_event_id"),
@javax.persistence.Index(columnList = "billing_recurrence_id")
@Index(columnList = "registrarId"),
@Index(columnList = "eventTime"),
@Index(columnList = "domainRepoId"),
@Index(columnList = "billingTime"),
@Index(columnList = "billing_event_id"),
@Index(columnList = "billing_recurrence_id")
})
@AttributeOverride(name = "id", column = @Column(name = "billing_cancellation_id"))
@WithLongVKey(compositeKey = true)
public static class Cancellation extends BillingEvent {
/** The billing time of the charge that is being cancelled. */
@Index
DateTime billingTime;
/**
* The one-time billing event to cancel, or null for autorenew cancellations.
*
* <p>Although the type is {@link Key} the name "ref" is preserved for historical reasons.
* <p>Although the type is {@link VKey} the name "ref" is preserved for historical reasons.
*/
@IgnoreSave(IfNull.class)
BillingEventVKey refOneTime = null;
@Column(name = "billing_event_id")
VKey<OneTime> refOneTime;
/**
* The recurring billing event to cancel, or null for non-autorenew cancellations.
*
* <p>Although the type is {@link Key} the name "ref" is preserved for historical reasons.
* <p>Although the type is {@link VKey} the name "ref" is preserved for historical reasons.
*/
@IgnoreSave(IfNull.class)
BillingRecurrenceVKey refRecurring = null;
@Column(name = "billing_recurrence_id")
VKey<Recurring> refRecurring;
public DateTime getBillingTime() {
return billingTime;
}
public VKey<? extends BillingEvent> getEventKey() {
return firstNonNull(refOneTime, refRecurring).createVKey();
return firstNonNull(refOneTime, refRecurring);
}
/** The mapping from billable grace period types to originating billing event reasons. */
@@ -723,22 +647,23 @@ public abstract class BillingEvent extends ImmutableObject
* using the supplied targetId and deriving other metadata (clientId, billing time, and the
* cancellation reason) from the grace period.
*/
public static BillingEvent.Cancellation forGracePeriod(
public static Cancellation forGracePeriod(
GracePeriod gracePeriod,
DateTime eventTime,
Key<DomainHistory> domainHistoryKey,
DomainHistoryId domainHistoryId,
String targetId) {
checkArgument(gracePeriod.hasBillingEvent(),
checkArgument(
gracePeriod.hasBillingEvent(),
"Cannot create cancellation for grace period without billing event");
BillingEvent.Cancellation.Builder builder =
new BillingEvent.Cancellation.Builder()
Builder builder =
new Builder()
.setReason(checkNotNull(GRACE_PERIOD_TO_REASON.get(gracePeriod.getType())))
.setTargetId(targetId)
.setRegistrarId(gracePeriod.getRegistrarId())
.setEventTime(eventTime)
// The charge being cancelled will take place at the grace period's expiration time.
.setBillingTime(gracePeriod.getExpirationTime())
.setParent(domainHistoryKey);
.setDomainHistoryId(domainHistoryId);
// Set the grace period's billing event using the appropriate Cancellation builder method.
if (gracePeriod.getOneTimeBillingEvent() != null) {
builder.setOneTimeEventKey(gracePeriod.getOneTimeBillingEvent());
@@ -750,11 +675,11 @@ public abstract class BillingEvent extends ImmutableObject
@Override
public VKey<Cancellation> createVKey() {
return VKey.create(Cancellation.class, getId(), Key.create(this));
return createVKey(getId());
}
public static VKey<Cancellation> createVKey(Key<Cancellation> key) {
return VKey.create(Cancellation.class, key.getId(), key);
public static VKey<Cancellation> createVKey(long id) {
return VKey.createSql(Cancellation.class, id);
}
@Override
@@ -776,13 +701,13 @@ public abstract class BillingEvent extends ImmutableObject
return this;
}
public Builder setOneTimeEventKey(VKey<BillingEvent.OneTime> eventKey) {
getInstance().refOneTime = BillingEventVKey.create(eventKey);
public Builder setOneTimeEventKey(VKey<OneTime> eventKey) {
getInstance().refOneTime = eventKey;
return this;
}
public Builder setRecurringEventKey(VKey<BillingEvent.Recurring> eventKey) {
getInstance().refRecurring = BillingRecurrenceVKey.create(eventKey);
public Builder setRecurringEventKey(VKey<Recurring> eventKey) {
getInstance().refRecurring = eventKey;
return this;
}
@@ -791,115 +716,11 @@ public abstract class BillingEvent extends ImmutableObject
Cancellation instance = getInstance();
checkNotNull(instance.billingTime, "Must set billing time");
checkNotNull(instance.reason, "Must set reason");
checkState((instance.refOneTime == null) != (instance.refRecurring == null),
checkState(
(instance.refOneTime == null) != (instance.refRecurring == null),
"Cancellations must have exactly one billing event key set");
return super.build();
}
}
}
/** An event representing a modification of an existing one-time billing event. */
@ReportedOn
@Entity
@WithLongVKey(compositeKey = true)
public static class Modification extends BillingEvent {
/** The change in cost that should be applied to the original billing event. */
Money cost;
/** The one-time billing event to modify. */
Key<BillingEvent.OneTime> eventRef;
/**
* Description of the modification (and presumably why it was issued). This text may appear as a
* line item on an invoice or report about such modifications.
*/
String description;
public Money getCost() {
return cost;
}
public Key<BillingEvent.OneTime> getEventKey() {
return eventRef;
}
public String getDescription() {
return description;
}
@Override
public Builder asBuilder() {
return new Builder(clone(this));
}
@Override
public VKey<Modification> createVKey() {
return VKey.create(Modification.class, getId(), Key.create(this));
}
public static VKey<Modification> createVKey(Key<Modification> key) {
return VKey.create(Modification.class, key.getId(), key);
}
/**
* Create a new Modification billing event which is a refund of the given OneTime billing event
* and that is parented off the given HistoryEntry.
*
* <p>Note that this method may appear to be unused most of the time, but it is kept around
* because it is needed by one-off scrap tools that need to make billing adjustments.
*/
public static Modification createRefundFor(
OneTime billingEvent, DomainHistory historyEntry, String description) {
return new Builder()
.setRegistrarId(billingEvent.getRegistrarId())
.setFlags(billingEvent.getFlags())
.setReason(billingEvent.getReason())
.setTargetId(billingEvent.getTargetId())
.setEventKey(Key.create(billingEvent))
.setEventTime(historyEntry.getModificationTime())
.setDescription(description)
.setCost(billingEvent.getCost().negated())
.setParent(historyEntry)
.build();
}
/** A builder for {@link Modification} since it is immutable. */
public static class Builder extends BillingEvent.Builder<Modification, Builder> {
public Builder() {}
private Builder(Modification instance) {
super(instance);
}
public Builder setCost(Money cost) {
getInstance().cost = cost;
return this;
}
public Builder setEventKey(Key<BillingEvent.OneTime> eventKey) {
getInstance().eventRef = eventKey;
return this;
}
public Builder setDescription(String description) {
getInstance().description = description;
return this;
}
@Override
public Modification build() {
Modification instance = getInstance();
checkNotNull(instance.reason);
checkNotNull(instance.eventRef);
BillingEvent.OneTime billingEvent =
tm().transact(() -> tm().loadByKey(VKey.from(instance.eventRef)));
checkArgument(
Objects.equals(instance.cost.getCurrencyUnit(), billingEvent.cost.getCurrencyUnit()),
"Referenced billing event is in a different currency");
return super.build();
}
}
}
}
@@ -19,8 +19,8 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainContent;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.GracePeriod.GracePeriodHistory;
@@ -33,14 +33,14 @@ import google.registry.persistence.transaction.JpaTransactionManager;
/**
* Utilities for managing an alternative JPA entity model optimized for bulk loading multi-level
* entities such as {@link DomainBase} and {@link DomainHistory}.
* entities such as {@link Domain} and {@link DomainHistory}.
*
* <p>In a bulk query for a multi-level JPA entity type, the JPA framework only generates a bulk
* query (SELECT * FROM table) for the base table. Then, for each row in the base table, additional
* queries are issued to load associated rows in child tables. This can be very slow when an entity
* type has multiple child tables.
*
* <p>We have defined an alternative entity model for {@code DomainBase} and {@code DomainHistory},
* <p>We have defined an alternative entity model for {@link Domain} and {@link DomainHistory},
* where the base table as well as the child tables are mapped to single-level entity types. The
* idea is to load each of these types using a bulk query, and assemble them into the target type in
* memory in a pipeline. The main use case is Datastore-Cloud SQL validation during the Registry
@@ -53,8 +53,8 @@ public class BulkQueryEntities {
*/
public static final ImmutableMap<String, String> JPA_ENTITIES_REPLACEMENTS =
ImmutableMap.of(
DomainBase.class.getCanonicalName(),
DomainBaseLite.class.getCanonicalName(),
Domain.class.getCanonicalName(),
DomainLite.class.getCanonicalName(),
DomainHistory.class.getCanonicalName(),
DomainHistoryLite.class.getCanonicalName());
@@ -64,18 +64,18 @@ public class BulkQueryEntities {
ImmutableList.of(
DomainHost.class.getCanonicalName(), DomainHistoryHost.class.getCanonicalName());
public static DomainBase assembleDomainBase(
DomainBaseLite domainBaseLite,
public static Domain assembleDomain(
DomainLite domainLite,
ImmutableSet<GracePeriod> gracePeriods,
ImmutableSet<DelegationSignerData> delegationSignerData,
ImmutableSet<VKey<HostResource>> nsHosts) {
DomainBase.Builder builder = new DomainBase.Builder();
builder.copyFrom(domainBaseLite);
Domain.Builder builder = new Domain.Builder();
builder.copyFrom(domainLite);
builder.setGracePeriods(gracePeriods);
builder.setDsData(delegationSignerData);
builder.setNameservers(nsHosts);
// Restore the original update timestamp (this gets cleared when we set nameservers or DS data).
builder.setUpdateTimestamp(domainBaseLite.getUpdateTimestamp());
builder.setUpdateTimestamp(domainLite.getUpdateTimestamp());
return builder.build();
}
@@ -87,11 +87,11 @@ public class BulkQueryEntities {
ImmutableSet<DomainTransactionRecord> transactionRecords) {
DomainHistory.Builder builder = new DomainHistory.Builder();
builder.copyFrom(domainHistoryLite);
DomainContent rawDomainContent = domainHistoryLite.domainContent;
if (rawDomainContent != null) {
DomainContent newDomainContent =
DomainBase rawDomainBase = domainHistoryLite.domainBase;
if (rawDomainBase != null) {
DomainBase newDomainBase =
domainHistoryLite
.domainContent
.domainBase
.asBuilder()
.setNameservers(domainHistoryHosts)
.setGracePeriods(
@@ -104,9 +104,9 @@ public class BulkQueryEntities {
.collect(toImmutableSet()))
// Restore the original update timestamp (this gets cleared when we set nameservers or
// DS data).
.setUpdateTimestamp(domainHistoryLite.domainContent.getUpdateTimestamp())
.setUpdateTimestamp(domainHistoryLite.domainBase.getUpdateTimestamp())
.build();
builder.setDomain(newDomainContent);
builder.setDomain(newDomainBase);
}
return builder.buildAndAssemble(
dsDataHistories, domainHistoryHosts, gracePeriodHistories, transactionRecords);
@@ -15,8 +15,8 @@
package google.registry.model.bulkquery;
import com.googlecode.objectify.Key;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainContent;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.domain.Period;
@@ -49,9 +49,9 @@ import javax.persistence.PostLoad;
@IdClass(DomainHistoryId.class)
public class DomainHistoryLite extends HistoryEntry {
// Store DomainContent instead of DomainBase so we don't pick up its @Id
// Store DomainBase instead of Domain so we don't pick up its @Id
// Nullable for the sake of pre-Registry-3.0 history objects
@Nullable DomainContent domainContent;
@Nullable DomainBase domainBase;
@Id
@Access(AccessType.PROPERTY)
@@ -64,7 +64,7 @@ public class DomainHistoryLite extends HistoryEntry {
/** This method is private because it is only used by Hibernate. */
@SuppressWarnings("unused")
private void setDomainRepoId(String domainRepoId) {
parent = Key.create(DomainBase.class, domainRepoId);
parent = Key.create(Domain.class, domainRepoId);
}
@Override
@@ -101,9 +101,9 @@ public class DomainHistoryLite extends HistoryEntry {
return super.getId();
}
/** The key to the {@link DomainBase} this is based off of. */
public VKey<DomainBase> getParentVKey() {
return VKey.create(DomainBase.class, getDomainRepoId());
/** The key to the {@link Domain} this is based off of. */
public VKey<Domain> getParentVKey() {
return VKey.create(Domain.class, getDomainRepoId());
}
public DomainHistoryId getDomainHistoryId() {
@@ -112,14 +112,14 @@ public class DomainHistoryLite extends HistoryEntry {
@PostLoad
void postLoad() {
if (domainContent == null) {
if (domainBase == null) {
return;
}
// See inline comments in DomainHistory.postLoad for reasons for the following lines.
if (domainContent.getDomainName() == null) {
domainContent = null;
} else if (domainContent.getRepoId() == null) {
domainContent.setRepoId(parent.getName());
if (domainBase.getDomainName() == null) {
domainBase = null;
} else if (domainBase.getRepoId() == null) {
domainBase.setRepoId(parent.getName());
}
}
}
@@ -14,8 +14,8 @@
package google.registry.model.bulkquery;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainContent;
import google.registry.persistence.VKey;
import google.registry.persistence.WithStringVKey;
import javax.persistence.Access;
@@ -23,17 +23,17 @@ import javax.persistence.AccessType;
import javax.persistence.Entity;
/**
* A 'light' version of {@link DomainBase} with only base table ("Domain") attributes, which allows
* fast bulk loading. They are used in in-memory assembly of {@code DomainBase} instances along with
* A 'light' version of {@link Domain} with only base table ("Domain") attributes, which allows fast
* bulk loading. They are used in in-memory assembly of {@code Domain} instances along with
* bulk-loaded child entities ({@code GracePeriod} etc). The in-memory assembly achieves much higher
* performance than loading {@code DomainBase} directly.
* performance than loading {@code Domain} directly.
*
* <p>Please refer to {@link BulkQueryEntities} for more information.
*/
@Entity(name = "Domain")
@WithStringVKey
@Access(AccessType.FIELD)
public class DomainBaseLite extends DomainContent {
public class DomainLite extends DomainBase {
@Override
@javax.persistence.Id
@@ -42,7 +42,7 @@ public class DomainBaseLite extends DomainContent {
return super.getRepoId();
}
public static VKey<DomainBaseLite> createVKey(String repoId) {
return VKey.createSql(DomainBaseLite.class, repoId);
public static VKey<DomainLite> createVKey(String repoId) {
return VKey.createSql(DomainLite.class, repoId);
}
}
@@ -53,12 +53,16 @@ public class ClassPathManager {
}
public static <T> Class<T> getClass(String className) {
checkArgument(CLASS_REGISTRY.containsKey(className), "Class not found in class registry");
checkArgument(
CLASS_REGISTRY.containsKey(className), "Class %s not found in class registry", className);
return (Class<T>) CLASS_REGISTRY.get(className);
}
public static <T> String getClassName(Class<T> clazz) {
checkArgument(CLASS_NAME_REGISTRY.containsKey(clazz), "Class not found in class name registry");
checkArgument(
CLASS_NAME_REGISTRY.containsKey(clazz),
"Class %s not found in class name registry",
clazz.getSimpleName());
return CLASS_NAME_REGISTRY.get(clazz);
}
}
@@ -197,7 +197,7 @@ public class DatabaseMigrationStateSchedule extends CrossTldSingleton {
MigrationState.DATASTORE_ONLY,
"migrationTransitionMap must start with DATASTORE_ONLY");
validateTransitionAtCurrentTime(transitions);
jpaTm().putWithoutBackup(new DatabaseMigrationStateSchedule(transitions));
jpaTm().put(new DatabaseMigrationStateSchedule(transitions));
CACHE.invalidateAll();
}
@@ -0,0 +1,216 @@
// Copyright 2017 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.domain;
import com.googlecode.objectify.Key;
import google.registry.model.EppResource;
import google.registry.model.EppResource.ForeignKeyedEppResource;
import google.registry.model.annotations.ExternalMessagingName;
import google.registry.model.annotations.ReportedOn;
import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.host.HostResource;
import google.registry.persistence.VKey;
import google.registry.persistence.WithStringVKey;
import java.util.Set;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.PostLoad;
import javax.persistence.Table;
import org.hibernate.Hibernate;
import org.joda.time.DateTime;
/**
* A persistable domain resource including mutable and non-mutable fields.
*
* @see <a href="https://tools.ietf.org/html/rfc5731">RFC 5731</a>
*/
@ReportedOn
@com.googlecode.objectify.annotation.Entity
@Entity
@Table(
name = "Domain",
indexes = {
@Index(columnList = "adminContact"),
@Index(columnList = "autorenewEndTime"),
@Index(columnList = "billingContact"),
@Index(columnList = "creationTime"),
@Index(columnList = "currentSponsorRegistrarId"),
@Index(columnList = "deletionTime"),
@Index(columnList = "domainName"),
@Index(columnList = "techContact"),
@Index(columnList = "tld"),
@Index(columnList = "registrantContact"),
@Index(columnList = "dnsRefreshRequestTime"),
@Index(columnList = "billing_recurrence_id"),
@Index(columnList = "transfer_billing_event_id"),
@Index(columnList = "transfer_billing_recurrence_id")
})
@WithStringVKey
@ExternalMessagingName("domain")
@Access(AccessType.FIELD)
public class Domain extends DomainBase implements ForeignKeyedEppResource {
@Override
@javax.persistence.Id
@Access(AccessType.PROPERTY)
public String getRepoId() {
return super.getRepoId();
}
// It seems like this should be FetchType.EAGER, but for some reason when we do that we get a lazy
// load error during the load of a domain.
@ElementCollection
@JoinTable(
name = "DomainHost",
indexes = {
@Index(columnList = "domain_repo_id,host_repo_id", unique = true),
@Index(columnList = "host_repo_id")
})
@Access(AccessType.PROPERTY)
@Column(name = "host_repo_id")
public Set<VKey<HostResource>> getNsHosts() {
return super.nsHosts;
}
/**
* Returns the set of {@link GracePeriod} associated with the domain.
*
* <p>This is the getter method specific for Hibernate to access the field so it is set to
* private. The caller can use the public {@link #getGracePeriods()} to get the grace periods.
*
* <p>Note that we need to set `insertable = false, updatable = false` for @JoinColumn, otherwise
* Hibernate would try to set the foreign key to null(through an UPDATE TABLE sql) instead of
* deleting the whole entry from the table when the {@link GracePeriod} is removed from the set.
*/
@Access(AccessType.PROPERTY)
@OneToMany(
cascade = {CascadeType.ALL},
fetch = FetchType.EAGER,
orphanRemoval = true)
@JoinColumn(
name = "domainRepoId",
referencedColumnName = "repoId",
insertable = false,
updatable = false)
@SuppressWarnings("UnusedMethod")
private Set<GracePeriod> getInternalGracePeriods() {
return gracePeriods;
}
/**
* Returns the set of {@link DelegationSignerData} associated with the domain.
*
* <p>This is the getter method specific for Hibernate to access the field so it is set to
* private. The caller can use the public {@link #getDsData()} to get the DS data.
*
* <p>Note that we need to set `insertable = false, updatable = false` for @JoinColumn, otherwise
* Hibernate would try to set the foreign key to null(through an UPDATE TABLE sql) instead of
* deleting the whole entry from the table when the {@link DelegationSignerData} is removed from
* the set.
*/
@Access(AccessType.PROPERTY)
@OneToMany(
cascade = {CascadeType.ALL},
fetch = FetchType.EAGER,
orphanRemoval = true)
@JoinColumn(
name = "domainRepoId",
referencedColumnName = "repoId",
insertable = false,
updatable = false)
@SuppressWarnings("UnusedMethod")
private Set<DelegationSignerData> getInternalDelegationSignerData() {
return dsData;
}
/** Post-load method to eager load the collections. */
@PostLoad
protected void postLoad() {
// TODO(b/188044616): Determine why Eager loading doesn't work here.
Hibernate.initialize(dsData);
Hibernate.initialize(gracePeriods);
}
@Override
public VKey<Domain> createVKey() {
return VKey.create(Domain.class, getRepoId(), Key.create(this));
}
@Override
public Domain cloneProjectedAtTime(final DateTime now) {
return cloneDomainProjectedAtTime(this, now);
}
public static VKey<Domain> createVKey(Key<Domain> key) {
return VKey.create(Domain.class, key.getName(), key);
}
/** An override of {@link EppResource#asBuilder} with tighter typing. */
@Override
public Builder asBuilder() {
return new Builder(clone(this));
}
/** A builder for constructing {@link Domain}, since it is immutable. */
public static class Builder extends DomainBase.Builder<Domain, Builder> {
public Builder() {}
Builder(Domain instance) {
super(instance);
}
public Builder copyFrom(DomainBase domainBase) {
this.getInstance().copyUpdateTimestamp(domainBase);
return this.setAuthInfo(domainBase.getAuthInfo())
.setAutorenewPollMessage(
domainBase.getAutorenewPollMessage(), domainBase.getAutorenewPollMessageHistoryId())
.setAutorenewBillingEvent(domainBase.getAutorenewBillingEvent())
.setAutorenewEndTime(domainBase.getAutorenewEndTime())
.setContacts(domainBase.getContacts())
.setCreationRegistrarId(domainBase.getCreationRegistrarId())
.setCreationTime(domainBase.getCreationTime())
.setDomainName(domainBase.getDomainName())
.setDeletePollMessage(domainBase.getDeletePollMessage())
.setDsData(domainBase.getDsData())
.setDeletionTime(domainBase.getDeletionTime())
.setGracePeriods(domainBase.getGracePeriods())
.setIdnTableName(domainBase.getIdnTableName())
.setLastTransferTime(domainBase.getLastTransferTime())
.setLaunchNotice(domainBase.getLaunchNotice())
.setLastEppUpdateRegistrarId(domainBase.getLastEppUpdateRegistrarId())
.setLastEppUpdateTime(domainBase.getLastEppUpdateTime())
.setNameservers(domainBase.getNameservers())
.setPersistedCurrentSponsorRegistrarId(domainBase.getPersistedCurrentSponsorRegistrarId())
.setRegistrant(domainBase.getRegistrant())
.setRegistrationExpirationTime(domainBase.getRegistrationExpirationTime())
.setRepoId(domainBase.getRepoId())
.setSmdId(domainBase.getSmdId())
.setSubordinateHosts(domainBase.getSubordinateHosts())
.setStatusValues(domainBase.getStatusValues())
.setTransferData(domainBase.getTransferData())
.setDnsRefreshRequestTime(domainBase.getDnsRefreshRequestTime());
}
}
}
File diff suppressed because it is too large Load Diff
@@ -54,7 +54,7 @@ import javax.xml.bind.annotation.XmlValue;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
/** A collection of {@link DomainBase} commands. */
/** A collection of {@link Domain} commands. */
public class DomainCommand {
/** The default validity period (if not specified) is 1 year for all operations. */
@@ -72,7 +72,7 @@ public class DomainCommand {
/** The fields on "chgType" from <a href="http://tools.ietf.org/html/rfc5731">RFC5731</a>. */
@XmlTransient
public static class DomainCreateOrChange<B extends DomainBase.Builder> extends ImmutableObject
public static class DomainCreateOrChange<B extends Domain.Builder> extends ImmutableObject
implements ResourceCreateOrChange<B> {
/** The contactId of the registrant who registered this domain. */
@@ -100,7 +100,7 @@ public class DomainCommand {
}
/**
* A create command for a {@link DomainBase}, mapping "createType" from <a
* A create command for a {@link Domain}, mapping "createType" from <a
* href="http://tools.ietf.org/html/rfc5731">RFC5731</a>.
*/
@XmlRootElement
@@ -113,7 +113,7 @@ public class DomainCommand {
"foreignKeyedDesignatedContacts",
"authInfo"
})
public static class Create extends DomainCreateOrChange<DomainBase.Builder>
public static class Create extends DomainCreateOrChange<Domain.Builder>
implements CreateOrUpdate<Create> {
/** Fully qualified domain name, which serves as a unique identifier for this domain. */
@@ -196,11 +196,11 @@ public class DomainCommand {
}
}
/** A delete command for a {@link DomainBase}. */
/** A delete command for a {@link Domain}. */
@XmlRootElement
public static class Delete extends AbstractSingleResourceCommand {}
/** An info request for a {@link DomainBase}. */
/** An info request for a {@link Domain}. */
@XmlRootElement
public static class Info extends ImmutableObject implements SingleResourceCommand {
@@ -259,11 +259,11 @@ public class DomainCommand {
}
}
/** A check request for {@link DomainBase}. */
/** A check request for {@link Domain}. */
@XmlRootElement
public static class Check extends ResourceCheck {}
/** A renew command for a {@link DomainBase}. */
/** A renew command for a {@link Domain}. */
@XmlRootElement
public static class Renew extends AbstractSingleResourceCommand {
@XmlElement(name = "curExpDate")
@@ -281,7 +281,7 @@ public class DomainCommand {
}
}
/** A transfer operation for a {@link DomainBase}. */
/** A transfer operation for a {@link Domain}. */
@XmlRootElement
public static class Transfer extends AbstractSingleResourceCommand {
/** The period to extend this domain's registration upon completion of the transfer. */
@@ -300,11 +300,10 @@ public class DomainCommand {
}
}
/** An update to a {@link DomainBase}. */
/** An update to a {@link Domain}. */
@XmlRootElement
@XmlType(propOrder = {"targetId", "innerAdd", "innerRemove", "innerChange"})
public static class Update
extends ResourceUpdate<Update.AddRemove, DomainBase.Builder, Update.Change>
public static class Update extends ResourceUpdate<Update.AddRemove, Domain.Builder, Update.Change>
implements CreateOrUpdate<Update> {
@XmlElement(name = "chg")
@@ -383,7 +382,7 @@ public class DomainCommand {
/** The inner change type on a domain update command. */
@XmlType(propOrder = {"registrantContactId", "authInfo"})
public static class Change extends DomainCreateOrChange<DomainBase.Builder> {
public static class Change extends DomainCreateOrChange<Domain.Builder> {
/** Creates a copy of this {@link Change} with hard links to hosts and contacts. */
Change cloneAndLinkReferences(DateTime now) throws InvalidReferencesException {
Change clone = clone(this);
@@ -1,947 +0,0 @@
// Copyright 2017 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.domain;
import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Strings.emptyToNull;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;
import static com.google.common.collect.Sets.difference;
import static com.google.common.collect.Sets.intersection;
import static google.registry.model.EppResourceUtils.projectResourceOntoBuilderAtTime;
import static google.registry.model.EppResourceUtils.setAutomaticTransferSuccessProperties;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.CollectionUtils.forceEmptyToNull;
import static google.registry.util.CollectionUtils.nullToEmpty;
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
import static google.registry.util.CollectionUtils.union;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static google.registry.util.DateTimeUtils.earliestOf;
import static google.registry.util.DateTimeUtils.isBeforeOrAt;
import static google.registry.util.DateTimeUtils.leapSafeAddYears;
import static google.registry.util.DomainNameUtils.canonicalizeHostname;
import static google.registry.util.DomainNameUtils.getTldFromDomainName;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.Ignore;
import com.googlecode.objectify.annotation.IgnoreSave;
import com.googlecode.objectify.annotation.Index;
import com.googlecode.objectify.condition.IfNull;
import google.registry.dns.RefreshDnsAction;
import google.registry.flows.ResourceFlowUtils;
import google.registry.model.EppResource;
import google.registry.model.EppResource.ResourceWithTransferData;
import google.registry.model.billing.BillingEvent;
import google.registry.model.common.EntityGroupRoot;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.launch.LaunchNotice;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.HostResource;
import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.tld.Registry;
import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferStatus;
import google.registry.persistence.VKey;
import google.registry.util.CollectionUtils;
import google.registry.util.DateTimeUtils;
import java.util.HashSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nullable;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import org.hibernate.collection.internal.PersistentSet;
import org.joda.time.DateTime;
import org.joda.time.Interval;
/**
* A persistable domain resource including mutable and non-mutable fields.
*
* <p>This class deliberately does not include an {@link javax.persistence.Id} so that any
* foreign-keyed fields can refer to the proper parent entity's ID, whether we're storing this in
* the DB itself or as part of another entity.
*
* <p>For historical reasons, the name of this class is "DomainContent". Ideally it would be
* "DomainBase" for parallelism with the other {@link EppResource} entity classes, but because that
* name is already taken by {@link DomainBase} (also for historical reasons), we can't use it. Once
* we are no longer on Datastore, we can rename the classes.
*
* @see <a href="https://tools.ietf.org/html/rfc5731">RFC 5731</a>
*/
@MappedSuperclass
@Embeddable
@Access(AccessType.FIELD)
public class DomainContent extends EppResource
implements 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;
/** Status values which prohibit DNS information from being published. */
private static final ImmutableSet<StatusValue> DNS_PUBLISHING_PROHIBITED_STATUSES =
ImmutableSet.of(
StatusValue.CLIENT_HOLD,
StatusValue.INACTIVE,
StatusValue.PENDING_DELETE,
StatusValue.SERVER_HOLD);
/**
* Fully qualified domain name (puny-coded), which serves as the foreign key for this domain.
*
* <p>This is only unique in the sense that for any given lifetime specified as the time range
* from (creationTime, deletionTime) there can only be one domain in Datastore with this name.
* However, there can be many domains with the same name and non-overlapping lifetimes.
*
* @invariant fullyQualifiedDomainName == fullyQualifiedDomainName.toLowerCase(Locale.ENGLISH)
*/
// TODO(b/177567432): Rename this to domainName when we are off Datastore
@Column(name = "domainName")
@Index
String fullyQualifiedDomainName;
/** The top level domain this is under, dernormalized from {@link #fullyQualifiedDomainName}. */
@Index String tld;
/** References to hosts that are the nameservers for the domain. */
@EmptySetToNull @Index @Transient Set<VKey<HostResource>> nsHosts;
/** Contacts. */
VKey<ContactResource> adminContact;
VKey<ContactResource> billingContact;
VKey<ContactResource> techContact;
VKey<ContactResource> registrantContact;
/** Authorization info (aka transfer secret) of the domain. */
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "pw.value", column = @Column(name = "auth_info_value")),
@AttributeOverride(name = "pw.repoId", column = @Column(name = "auth_info_repo_id")),
})
DomainAuthInfo authInfo;
/** Data used to construct DS records for this domain. */
@Transient Set<DelegationSignerData> dsData;
/**
* The claims notice supplied when this domain was created, if there was one.
*
* <p>It's {@literal @}XmlTransient because it's not returned in an info response.
*/
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "noticeId.tcnId", column = @Column(name = "launch_notice_tcn_id")),
@AttributeOverride(
name = "noticeId.validatorId",
column = @Column(name = "launch_notice_validator_id")),
@AttributeOverride(
name = "expirationTime",
column = @Column(name = "launch_notice_expiration_time")),
@AttributeOverride(
name = "acceptedTime",
column = @Column(name = "launch_notice_accepted_time")),
})
LaunchNotice launchNotice;
/**
* Name of first IDN table associated with TLD that matched the characters in this domain label.
*
* @see google.registry.tldconfig.idn.IdnLabelValidator#findValidIdnTableForTld
*/
@IgnoreSave(IfNull.class)
String idnTableName;
/** Fully qualified host names of this domain's active subordinate hosts. */
Set<String> subordinateHosts;
/** When this domain's registration will expire. */
DateTime registrationExpirationTime;
/**
* The poll message associated with this domain being deleted.
*
* <p>This field should be null if the domain is not in pending delete. If it is, the field should
* refer to a {@link PollMessage} timed to when the domain is fully deleted. If the domain is
* restored, the message should be deleted.
*/
@Column(name = "deletion_poll_message_id")
VKey<PollMessage.OneTime> deletePollMessage;
/**
* The recurring billing event associated with this domain's autorenewals.
*
* <p>The recurrence should be open ended unless the domain is in pending delete or fully deleted,
* in which case it should be closed at the time the delete was requested. Whenever the domain's
* {@link #registrationExpirationTime} is changed the recurrence should be closed, a new one
* should be created, and this field should be updated to point to the new one.
*/
@Column(name = "billing_recurrence_id")
VKey<BillingEvent.Recurring> autorenewBillingEvent;
/**
* The recurring poll message associated with this domain's autorenewals.
*
* <p>The recurrence should be open ended unless the domain is in pending delete or fully deleted,
* in which case it should be closed at the time the delete was requested. Whenever the domain's
* {@link #registrationExpirationTime} is changed the recurrence should be closed, a new one
* should be created, and this field should be updated to point to the new one.
*/
@Column(name = "autorenew_poll_message_id")
VKey<PollMessage.Autorenew> autorenewPollMessage;
/**
* History record for the autorenew poll message.
*
* <p>Here so we can restore the original ofy key from sql.
*/
@Ignore Long autorenewPollMessageHistoryId;
/** The unexpired grace periods for this domain (some of which may not be active yet). */
@Transient Set<GracePeriod> gracePeriods;
/**
* The id of the signed mark that was used to create this domain in sunrise.
*
* <p>Will only be populated for domains created in sunrise.
*/
@IgnoreSave(IfNull.class)
String smdId;
/** Data about any pending or past transfers on this domain. */
DomainTransferData transferData;
/**
* The time that this resource was last transferred.
*
* <p>Can be null if the resource has never been transferred.
*/
DateTime lastTransferTime;
/**
* When the domain's autorenewal status will expire.
*
* <p>This will be {@link DateTimeUtils#END_OF_TIME} for the vast majority of domains because all
* domains autorenew indefinitely by default and autorenew can only be countermanded by
* administrators, typically for reasons of the URS process or termination of a registrar for
* nonpayment.
*
* <p>When a domain is scheduled to not autorenew, this field is set to the current value of its
* {@link #registrationExpirationTime}, after which point the next invocation of a periodic
* cronjob will explicitly delete the domain. This field is a DateTime and not a boolean because
* of edge cases that occur during the autorenew grace period. We need to be able to tell the
* difference domains that have reached their life and must be deleted now, and domains that
* happen to be in the autorenew grace period now but should be deleted in roughly a year.
*/
@Index DateTime autorenewEndTime;
/**
* When this domain's DNS was requested to be refreshed, or null if its DNS is up-to-date.
*
* <p>This will almost always be null except in the couple minutes' interval between when a
* DNS-affecting create or update operation takes place and when the {@link RefreshDnsAction}
* runs, which resets this back to null upon completion of the DNS refresh task. This is a {@link
* DateTime} rather than a simple dirty boolean so that the DNS refresh action can order by the
* DNS refresh request time and take action on the oldest ones first.
*
* <p>Note that this is a Cloud SQL-based replacement for the {@code dns-pull} task queue. The
* domains that have a non-null value for this field should be exactly the same as the tasks that
* would be in the {@code dns-pull} queue. Because this is Cloud SQL-specific, it is omitted from
* Datastore.
*
* <p>Note that in the {@link DomainHistory} table this value means something slightly different:
* It means that the given domain action requested a DNS update. Unlike on the {@code Domain}
* table, this value is not then subsequently nulled out once the DNS refresh is complete; rather,
* it remains as a permanent record of which actions were DNS-affecting and which were not.
*/
// TODO(mcilwain): Start using this field once we are further along in the DB migration.
@Ignore DateTime dnsRefreshRequestTime;
/**
* Returns the DNS refresh request time iff this domain's DNS needs refreshing, otherwise absent.
*/
public Optional<DateTime> getDnsRefreshRequestTime() {
return Optional.ofNullable(dnsRefreshRequestTime);
}
public static <T> VKey<T> restoreOfyFrom(Key<DomainBase> domainKey, VKey<T> key, Long historyId) {
if (historyId == null) {
// This is a legacy key (or a null key, in which case this works too)
return VKey.restoreOfyFrom(key, EntityGroupRoot.class, "per-tld");
} else {
return VKey.restoreOfyFrom(key, domainKey, HistoryEntry.class, historyId);
}
}
public ImmutableSet<String> getSubordinateHosts() {
return nullToEmptyImmutableCopy(subordinateHosts);
}
public DateTime getRegistrationExpirationTime() {
return registrationExpirationTime;
}
public VKey<PollMessage.OneTime> getDeletePollMessage() {
return deletePollMessage;
}
public VKey<BillingEvent.Recurring> getAutorenewBillingEvent() {
return autorenewBillingEvent;
}
public VKey<PollMessage.Autorenew> getAutorenewPollMessage() {
return autorenewPollMessage;
}
public Long getAutorenewPollMessageHistoryId() {
return autorenewPollMessageHistoryId;
}
public ImmutableSet<GracePeriod> getGracePeriods() {
return nullToEmptyImmutableCopy(gracePeriods);
}
public String getSmdId() {
return smdId;
}
/**
* Returns the autorenew end time if there is one, otherwise empty.
*
* <p>Note that {@link DateTimeUtils#END_OF_TIME} is used as a sentinel value in the database
* representation to signify that autorenew doesn't end, and is mapped to empty here for the
* purposes of more legible business logic.
*/
public Optional<DateTime> getAutorenewEndTime() {
return Optional.ofNullable(autorenewEndTime.equals(END_OF_TIME) ? null : autorenewEndTime);
}
@Override
public DomainTransferData getTransferData() {
return Optional.ofNullable(transferData).orElse(DomainTransferData.EMPTY);
}
@Override
public DateTime getLastTransferTime() {
return lastTransferTime;
}
@Override
public String getForeignKey() {
return fullyQualifiedDomainName;
}
public String getDomainName() {
return fullyQualifiedDomainName;
}
public ImmutableSet<DelegationSignerData> getDsData() {
return nullToEmptyImmutableCopy(dsData);
}
public LaunchNotice getLaunchNotice() {
return launchNotice;
}
public String getIdnTableName() {
return idnTableName;
}
public ImmutableSet<VKey<HostResource>> getNameservers() {
return nullToEmptyImmutableCopy(nsHosts);
}
// Hibernate needs this in order to populate nsHosts but no one else should ever use it
@SuppressWarnings("UnusedMethod")
private void setNsHosts(Set<VKey<HostResource>> nsHosts) {
this.nsHosts = forceEmptyToNull(nsHosts);
}
// Note: for the two methods below, how we wish to treat the Hibernate setters depends on the
// current state of the object and what's passed in. The key principle is that we wish to maintain
// the link between parent and child objects, meaning that we should keep around whichever of the
// two sets (the parameter vs the class variable and clear/populate that as appropriate.
//
// If the class variable is a PersistentSet and we overwrite it here, Hibernate will throw
// an exception "A collection with cascade=”all-delete-orphan” was no longer referenced by the
// owning entity instance". See https://stackoverflow.com/questions/5587482 for more details.
// Hibernate needs this in order to populate gracePeriods but no one else should ever use it
@SuppressWarnings("UnusedMethod")
private void setInternalGracePeriods(Set<GracePeriod> gracePeriods) {
if (this.gracePeriods instanceof PersistentSet) {
Set<GracePeriod> nonNullGracePeriods = nullToEmpty(gracePeriods);
this.gracePeriods.retainAll(nonNullGracePeriods);
this.gracePeriods.addAll(nonNullGracePeriods);
} else {
this.gracePeriods = gracePeriods;
}
}
// Hibernate needs this in order to populate dsData but no one else should ever use it
@SuppressWarnings("UnusedMethod")
private void setInternalDelegationSignerData(Set<DelegationSignerData> dsData) {
if (this.dsData instanceof PersistentSet) {
Set<DelegationSignerData> nonNullDsData = nullToEmpty(dsData);
this.dsData.retainAll(nonNullDsData);
this.dsData.addAll(nonNullDsData);
} else {
this.dsData = dsData;
}
}
public final String getCurrentSponsorRegistrarId() {
return getPersistedCurrentSponsorRegistrarId();
}
/** Returns true if DNS information should be published for the given domain. */
public boolean shouldPublishToDns() {
return intersection(getStatusValues(), DNS_PUBLISHING_PROHIBITED_STATUSES).isEmpty();
}
/**
* Returns the Registry Grace Period Statuses for this domain.
*
* <p>This collects all statuses from the domain's {@link GracePeriod} entries and also adds the
* PENDING_DELETE status if needed.
*/
public ImmutableSet<GracePeriodStatus> getGracePeriodStatuses() {
Set<GracePeriodStatus> gracePeriodStatuses = new HashSet<>();
for (GracePeriod gracePeriod : getGracePeriods()) {
gracePeriodStatuses.add(gracePeriod.getType());
}
if (getStatusValues().contains(StatusValue.PENDING_DELETE)
&& !gracePeriodStatuses.contains(GracePeriodStatus.REDEMPTION)) {
gracePeriodStatuses.add(GracePeriodStatus.PENDING_DELETE);
}
return ImmutableSet.copyOf(gracePeriodStatuses);
}
/** Returns the subset of grace periods having the specified type. */
public ImmutableSet<GracePeriod> getGracePeriodsOfType(GracePeriodStatus gracePeriodType) {
ImmutableSet.Builder<GracePeriod> builder = new ImmutableSet.Builder<>();
for (GracePeriod gracePeriod : getGracePeriods()) {
if (gracePeriod.getType() == gracePeriodType) {
builder.add(gracePeriod);
}
}
return builder.build();
}
@Override
public DomainContent cloneProjectedAtTime(final DateTime now) {
return cloneDomainProjectedAtTime(this, now);
}
/**
* The logic in this method, which handles implicit server approval of transfers, very closely
* parallels the logic in {@code DomainTransferApproveFlow} which handles explicit client
* approvals.
*/
static <T extends DomainContent> T cloneDomainProjectedAtTime(T domain, DateTime now) {
DomainTransferData transferData = domain.getTransferData();
DateTime transferExpirationTime = transferData.getPendingTransferExpirationTime();
// If there's a pending transfer that has expired, handle it.
if (TransferStatus.PENDING.equals(transferData.getTransferStatus())
&& isBeforeOrAt(transferExpirationTime, now)) {
// Project until just before the transfer time. This will handle the case of an autorenew
// before the transfer was even requested or during the request period.
// If the transfer time is precisely the moment that the domain expires, there will not be an
// autorenew billing event (since we end the recurrence at transfer time and recurrences are
// exclusive of their ending), and we can just proceed with the transfer.
T domainAtTransferTime =
cloneDomainProjectedAtTime(domain, transferExpirationTime.minusMillis(1));
DateTime expirationDate = transferData.getTransferredRegistrationExpirationTime();
if (expirationDate == null) {
// Extend the registration by the correct number of years from the expiration time
// that was current on the domain right before the transfer, capped at 10 years from
// the moment of the transfer.
expirationDate =
ResourceFlowUtils.computeExDateForApprovalTime(
domainAtTransferTime, transferExpirationTime, transferData.getTransferPeriod());
}
// If we are within an autorenew grace period, the transfer will subsume the autorenew. There
// will already be a cancellation written in advance by the transfer request flow, so we don't
// need to worry about billing, but we do need to cancel out the expiration time increase.
// The transfer period saved in the transfer data will be one year, unless the superuser
// extension set the transfer period to zero.
// Set the expiration, autorenew events, and grace period for the transfer. (Transfer ends
// all other graces).
Builder builder =
domainAtTransferTime
.asBuilder()
.setRegistrationExpirationTime(expirationDate)
// Set the speculatively-written new autorenew events as the domain's autorenew
// events.
.setAutorenewBillingEvent(transferData.getServerApproveAutorenewEvent())
.setAutorenewPollMessage(
transferData.getServerApproveAutorenewPollMessage(),
transferData.getServerApproveAutorenewPollMessageHistoryId());
if (transferData.getTransferPeriod().getValue() == 1) {
// 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.
builder.setGracePeriods(
ImmutableSet.of(
GracePeriod.create(
GracePeriodStatus.TRANSFER,
domain.getRepoId(),
transferExpirationTime.plus(
Registry.get(domain.getTld()).getTransferGracePeriodLength()),
transferData.getGainingRegistrarId(),
transferData.getServerApproveBillingEvent())));
} else {
// There won't be a billing event, so we don't need a grace period
builder.setGracePeriods(ImmutableSet.of());
}
// Set all remaining transfer properties.
setAutomaticTransferSuccessProperties(builder, transferData);
builder
.setLastEppUpdateTime(transferExpirationTime)
.setLastEppUpdateRegistrarId(transferData.getGainingRegistrarId());
// Finish projecting to now.
return (T) builder.build().cloneProjectedAtTime(now);
}
Optional<DateTime> newLastEppUpdateTime = Optional.empty();
// There is no transfer. Do any necessary autorenews for active domains.
Builder builder = domain.asBuilder();
if (isBeforeOrAt(domain.getRegistrationExpirationTime(), now)
&& END_OF_TIME.equals(domain.getDeletionTime())) {
// Autorenew by the number of years between the old expiration time and now.
DateTime lastAutorenewTime =
leapSafeAddYears(
domain.getRegistrationExpirationTime(),
new Interval(domain.getRegistrationExpirationTime(), now).toPeriod().getYears());
DateTime newExpirationTime = lastAutorenewTime.plusYears(1);
builder
.setRegistrationExpirationTime(newExpirationTime)
.addGracePeriod(
GracePeriod.createForRecurring(
GracePeriodStatus.AUTO_RENEW,
domain.getRepoId(),
lastAutorenewTime.plus(
Registry.get(domain.getTld()).getAutoRenewGracePeriodLength()),
domain.getCurrentSponsorRegistrarId(),
domain.getAutorenewBillingEvent()));
newLastEppUpdateTime = Optional.of(lastAutorenewTime);
}
// Remove any grace periods that have expired.
T almostBuilt = (T) builder.build();
builder = almostBuilt.asBuilder();
for (GracePeriod gracePeriod : almostBuilt.getGracePeriods()) {
if (isBeforeOrAt(gracePeriod.getExpirationTime(), now)) {
builder.removeGracePeriod(gracePeriod);
if (!newLastEppUpdateTime.isPresent()
|| isBeforeOrAt(newLastEppUpdateTime.get(), gracePeriod.getExpirationTime())) {
newLastEppUpdateTime = Optional.of(gracePeriod.getExpirationTime());
}
}
}
// It is possible that the lastEppUpdateClientId is different from current sponsor client
// id, so we have to do the comparison instead of having one variable just storing the most
// recent time.
if (newLastEppUpdateTime.isPresent()) {
if (domain.getLastEppUpdateTime() == null
|| newLastEppUpdateTime.get().isAfter(domain.getLastEppUpdateTime())) {
builder
.setLastEppUpdateTime(newLastEppUpdateTime.get())
.setLastEppUpdateRegistrarId(domain.getCurrentSponsorRegistrarId());
}
}
// Handle common properties like setting or unsetting linked status. This also handles the
// general case of pending transfers for other resource types, but since we've always handled
// a pending transfer by this point that's a no-op for domains.
projectResourceOntoBuilderAtTime(almostBuilt, builder, now);
return (T) builder.build();
}
/** Return what the expiration time would be if the given number of years were added to it. */
public static DateTime extendRegistrationWithCap(
DateTime now, DateTime currentExpirationTime, @Nullable Integer extendedRegistrationYears) {
// We must cap registration at the max years (aka 10), even if that truncates the last year.
return earliestOf(
leapSafeAddYears(
currentExpirationTime, Optional.ofNullable(extendedRegistrationYears).orElse(0)),
leapSafeAddYears(now, MAX_REGISTRATION_YEARS));
}
/** Loads and returns the fully qualified host names of all linked nameservers. */
public ImmutableSortedSet<String> loadNameserverHostNames() {
return tm().transact(
() ->
tm().loadByKeys(getNameservers()).values().stream()
.map(HostResource::getHostName)
.collect(toImmutableSortedSet(Ordering.natural())));
}
/** A key to the registrant who registered this domain. */
public VKey<ContactResource> getRegistrant() {
return registrantContact;
}
public VKey<ContactResource> getAdminContact() {
return adminContact;
}
public VKey<ContactResource> getBillingContact() {
return billingContact;
}
public VKey<ContactResource> getTechContact() {
return techContact;
}
/** Associated contacts for the domain (other than registrant). */
public ImmutableSet<DesignatedContact> getContacts() {
return getAllContacts(false);
}
public DomainAuthInfo getAuthInfo() {
return authInfo;
}
/** Returns all referenced contacts from this domain. */
public ImmutableSet<VKey<ContactResource>> getReferencedContacts() {
return nullToEmptyImmutableCopy(getAllContacts(true)).stream()
.map(DesignatedContact::getContactKey)
.filter(Objects::nonNull)
.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() {
return tld;
}
/**
* Sets the individual contact fields from {@code contacts}.
*
* <p>The registrant field is only set if {@code includeRegistrant} is true, as this field needs
* to be set in some circumstances but not in others.
*/
void setContactFields(Set<DesignatedContact> contacts, boolean includeRegistrant) {
// Set the individual contact fields.
billingContact = techContact = adminContact = null;
if (includeRegistrant) {
registrantContact = null;
}
HashSet<DesignatedContact.Type> contactsDiscovered = new HashSet<DesignatedContact.Type>();
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()) {
case BILLING:
billingContact = contact.getContactKey();
break;
case TECH:
techContact = contact.getContactKey();
break;
case ADMIN:
adminContact = contact.getContactKey();
break;
case REGISTRANT:
if (includeRegistrant) {
registrantContact = contact.getContactKey();
}
break;
default:
throw new IllegalArgumentException("Unknown contact resource type: " + contact.getType());
}
}
}
@Override
public VKey<DomainBase> createVKey() {
throw new UnsupportedOperationException(
"DomainContent is not an actual persisted entity you can create a key to;"
+ " use DomainBase instead");
}
/** Predicate to determine if a given {@link DesignatedContact} is the registrant. */
static final Predicate<DesignatedContact> IS_REGISTRANT =
(DesignatedContact contact) -> DesignatedContact.Type.REGISTRANT.equals(contact.type);
/** An override of {@link EppResource#asBuilder} with tighter typing. */
@Override
public Builder<? extends DomainContent, ?> asBuilder() {
return new Builder<>(clone(this));
}
/** A builder for constructing {@link DomainBase}, since it is immutable. */
public static class Builder<T extends DomainContent, B extends Builder<T, B>>
extends EppResource.Builder<T, B> implements BuilderWithTransferData<DomainTransferData, B> {
public Builder() {}
Builder(T instance) {
super(instance);
}
@Override
public T build() {
T instance = getInstance();
// If TransferData is totally empty, set it to null.
if (DomainTransferData.EMPTY.equals(getInstance().transferData)) {
setTransferData(null);
}
// A DomainBase has status INACTIVE if there are no nameservers.
if (getInstance().getNameservers().isEmpty()) {
addStatusValue(StatusValue.INACTIVE);
} else { // There are nameservers, so make sure INACTIVE isn't there.
removeStatusValue(StatusValue.INACTIVE);
}
// If there is no autorenew end time, set it to END_OF_TIME.
instance.autorenewEndTime = firstNonNull(getInstance().autorenewEndTime, END_OF_TIME);
checkArgumentNotNull(emptyToNull(instance.fullyQualifiedDomainName), "Missing domainName");
checkArgumentNotNull(instance.getRegistrant(), "Missing registrant");
instance.tld = getTldFromDomainName(instance.fullyQualifiedDomainName);
T newDomain = super.build();
// Hibernate throws exception if gracePeriods or dsData is null because we enabled all
// cascadable operations and orphan removal.
newDomain.gracePeriods =
newDomain.gracePeriods == null ? ImmutableSet.of() : newDomain.gracePeriods;
newDomain.dsData =
newDomain.dsData == null
? ImmutableSet.of()
: newDomain.dsData.stream()
.map(ds -> ds.cloneWithDomainRepoId(instance.getRepoId()))
.collect(toImmutableSet());
return newDomain;
}
public B setDomainName(String domainName) {
checkArgument(
domainName.equals(canonicalizeHostname(domainName)),
"Domain name %s not in puny-coded, lower-case form",
domainName);
getInstance().fullyQualifiedDomainName = domainName;
return thisCastToDerived();
}
public B setDsData(ImmutableSet<DelegationSignerData> dsData) {
getInstance().dsData = dsData;
getInstance().resetUpdateTimestamp();
return thisCastToDerived();
}
public B setRegistrant(VKey<ContactResource> registrant) {
// Set the registrant field specifically.
getInstance().registrantContact = registrant;
return thisCastToDerived();
}
public B setAuthInfo(DomainAuthInfo authInfo) {
getInstance().authInfo = authInfo;
return thisCastToDerived();
}
public B setNameservers(VKey<HostResource> nameserver) {
getInstance().nsHosts = ImmutableSet.of(nameserver);
getInstance().resetUpdateTimestamp();
return thisCastToDerived();
}
public B setNameservers(ImmutableSet<VKey<HostResource>> nameservers) {
getInstance().nsHosts = forceEmptyToNull(nameservers);
getInstance().resetUpdateTimestamp();
return thisCastToDerived();
}
public B addNameserver(VKey<HostResource> nameserver) {
return addNameservers(ImmutableSet.of(nameserver));
}
public B addNameservers(ImmutableSet<VKey<HostResource>> nameservers) {
return setNameservers(
ImmutableSet.copyOf(Sets.union(getInstance().getNameservers(), nameservers)));
}
public B removeNameserver(VKey<HostResource> nameserver) {
return removeNameservers(ImmutableSet.of(nameserver));
}
public B removeNameservers(ImmutableSet<VKey<HostResource>> nameservers) {
return setNameservers(
ImmutableSet.copyOf(difference(getInstance().getNameservers(), nameservers)));
}
public B setContacts(DesignatedContact contact) {
return setContacts(ImmutableSet.of(contact));
}
public B setContacts(ImmutableSet<DesignatedContact> contacts) {
checkArgument(contacts.stream().noneMatch(IS_REGISTRANT), "Registrant cannot be a contact");
// Set the individual fields.
getInstance().setContactFields(contacts, false);
return thisCastToDerived();
}
public B addContacts(ImmutableSet<DesignatedContact> contacts) {
return setContacts(ImmutableSet.copyOf(Sets.union(getInstance().getContacts(), contacts)));
}
public B removeContacts(ImmutableSet<DesignatedContact> contacts) {
return setContacts(ImmutableSet.copyOf(difference(getInstance().getContacts(), contacts)));
}
public B setLaunchNotice(LaunchNotice launchNotice) {
getInstance().launchNotice = launchNotice;
return thisCastToDerived();
}
public B setIdnTableName(String idnTableName) {
getInstance().idnTableName = idnTableName;
return thisCastToDerived();
}
public B setSubordinateHosts(ImmutableSet<String> subordinateHosts) {
getInstance().subordinateHosts = subordinateHosts;
return thisCastToDerived();
}
public B addSubordinateHost(String hostToAdd) {
return setSubordinateHosts(
ImmutableSet.copyOf(union(getInstance().getSubordinateHosts(), hostToAdd)));
}
public B removeSubordinateHost(String hostToRemove) {
return setSubordinateHosts(
ImmutableSet.copyOf(
CollectionUtils.difference(getInstance().getSubordinateHosts(), hostToRemove)));
}
public B setRegistrationExpirationTime(DateTime registrationExpirationTime) {
getInstance().registrationExpirationTime = registrationExpirationTime;
return thisCastToDerived();
}
public B setDeletePollMessage(VKey<PollMessage.OneTime> deletePollMessage) {
getInstance().deletePollMessage = deletePollMessage;
return thisCastToDerived();
}
public B setAutorenewBillingEvent(VKey<BillingEvent.Recurring> autorenewBillingEvent) {
getInstance().autorenewBillingEvent = autorenewBillingEvent;
return thisCastToDerived();
}
public B setAutorenewPollMessage(
@Nullable VKey<PollMessage.Autorenew> autorenewPollMessage,
@Nullable Long autorenewPollMessageHistoryId) {
getInstance().autorenewPollMessage = autorenewPollMessage;
getInstance().autorenewPollMessageHistoryId = autorenewPollMessageHistoryId;
return thisCastToDerived();
}
public B setDnsRefreshRequestTime(Optional<DateTime> dnsRefreshRequestTime) {
getInstance().dnsRefreshRequestTime = dnsRefreshRequestTime.orElse(null);
return thisCastToDerived();
}
public B setSmdId(String smdId) {
getInstance().smdId = smdId;
return thisCastToDerived();
}
public B setGracePeriods(ImmutableSet<GracePeriod> gracePeriods) {
getInstance().gracePeriods = gracePeriods;
getInstance().resetUpdateTimestamp();
return thisCastToDerived();
}
public B addGracePeriod(GracePeriod gracePeriod) {
getInstance().gracePeriods = union(getInstance().getGracePeriods(), gracePeriod);
getInstance().resetUpdateTimestamp();
return thisCastToDerived();
}
public B removeGracePeriod(GracePeriod gracePeriod) {
getInstance().gracePeriods =
CollectionUtils.difference(getInstance().getGracePeriods(), gracePeriod);
getInstance().resetUpdateTimestamp();
return thisCastToDerived();
}
/**
* Sets the autorenew end time, or clears it if empty is passed.
*
* <p>Note that {@link DateTimeUtils#END_OF_TIME} is used as a sentinel value in the database
* representation to signify that autorenew doesn't end, and is mapped to empty here for the
* purposes of more legible business logic.
*/
public B setAutorenewEndTime(Optional<DateTime> autorenewEndTime) {
getInstance().autorenewEndTime = autorenewEndTime.orElse(END_OF_TIME);
return thisCastToDerived();
}
@Override
public B setTransferData(DomainTransferData transferData) {
getInstance().transferData = transferData;
return thisCastToDerived();
}
@Override
public B setLastTransferTime(DateTime lastTransferTime) {
getInstance().lastTransferTime = lastTransferTime;
return thisCastToDerived();
}
}
}
@@ -59,8 +59,8 @@ import org.hibernate.Hibernate;
* A persisted history entry representing an EPP modification to a domain.
*
* <p>In addition to the general history fields (e.g. action time, registrar ID) we also persist a
* copy of the domain entity at this point in time. We persist a raw {@link DomainContent} so that
* the foreign-keyed fields in that class can refer to this object.
* copy of the domain entity at this point in time. We persist a raw {@link DomainBase} so that the
* foreign-keyed fields in that class can refer to this object.
*
* <p>This class is only marked as a Datastore entity subclass and registered with Objectify so that
* when building it its ID can be auto-populated by Objectify. It is converted to its superclass
@@ -80,9 +80,9 @@ import org.hibernate.Hibernate;
@IdClass(DomainHistoryId.class)
public class DomainHistory extends HistoryEntry {
// Store DomainContent instead of DomainBase so we don't pick up its @Id
// Store DomainBase instead of Domain so we don't pick up its @Id
// Nullable for the sake of pre-Registry-3.0 history objects
@DoNotCompare @Nullable DomainContent domainContent;
@DoNotCompare @Nullable DomainBase domainBase;
@Id
@Access(AccessType.PROPERTY)
@@ -95,12 +95,12 @@ public class DomainHistory extends HistoryEntry {
/** This method is private because it is only used by Hibernate. */
@SuppressWarnings("unused")
private void setDomainRepoId(String domainRepoId) {
parent = Key.create(DomainBase.class, domainRepoId);
parent = Key.create(Domain.class, domainRepoId);
}
// We could have reused domainContent.nsHosts here, but Hibernate throws a weird exception after
// We could have reused domainBase.nsHosts here, but Hibernate throws a weird exception after
// we change to use a composite primary key.
// TODO(b/166776754): Investigate if we can reuse domainContent.nsHosts for storing host keys.
// TODO(b/166776754): Investigate if we can reuse domainBase.nsHosts for storing host keys.
@DoNotCompare
@ElementCollection
@JoinTable(
@@ -232,18 +232,18 @@ public class DomainHistory extends HistoryEntry {
}
/**
* The values of all the fields on the {@link DomainContent} object after the action represented
* by this history object was executed.
* The values of all the fields on the {@link DomainBase} object after the action represented by
* this history object was executed.
*
* <p>Will be absent for objects created prior to the Registry 3.0 SQL migration.
*/
public Optional<DomainContent> getDomainContent() {
return Optional.ofNullable(domainContent);
public Optional<DomainBase> getDomainBase() {
return Optional.ofNullable(domainBase);
}
/** The key to the {@link DomainBase} this is based off of. */
public VKey<DomainBase> getParentVKey() {
return VKey.create(DomainBase.class, getDomainRepoId());
/** The key to the {@link Domain} this is based off of. */
public VKey<Domain> getParentVKey() {
return VKey.create(Domain.class, getDomainRepoId());
}
public Set<GracePeriodHistory> getGracePeriodHistories() {
@@ -259,8 +259,7 @@ public class DomainHistory extends HistoryEntry {
@Override
public Optional<? extends EppResource> getResourceAtPointInTime() {
return getDomainContent()
.map(domainContent -> new DomainBase.Builder().copyFrom(domainContent).build());
return getDomainBase().map(domainBase -> new Domain.Builder().copyFrom(domainBase).build());
}
@PostLoad
@@ -271,39 +270,39 @@ public class DomainHistory extends HistoryEntry {
Hibernate.initialize(dsDataHistories);
Hibernate.initialize(gracePeriodHistories);
if (domainContent != null) {
domainContent.nsHosts = nullToEmptyImmutableCopy(nsHosts);
domainContent.gracePeriods =
if (domainBase != null) {
domainBase.nsHosts = nullToEmptyImmutableCopy(nsHosts);
domainBase.gracePeriods =
gracePeriodHistories.stream()
.map(GracePeriod::createFromHistory)
.collect(toImmutableSet());
domainContent.dsData =
domainBase.dsData =
dsDataHistories.stream().map(DelegationSignerData::create).collect(toImmutableSet());
// Normally Hibernate would see that the domain fields are all null and would fill
// domainContent with a null object. Unfortunately, the updateTimestamp is never null in SQL.
if (domainContent.getDomainName() == null) {
domainContent = null;
// domainBase with a null object. Unfortunately, the updateTimestamp is never null in SQL.
if (domainBase.getDomainName() == null) {
domainBase = null;
} else {
if (domainContent.getRepoId() == null) {
// domainContent still hasn't been fully constructed yet, so it's ok to go in and mutate
if (domainBase.getRepoId() == null) {
// domainBase still hasn't been fully constructed yet, so it's ok to go in and mutate
// it. In fact, we have to because going through the builder causes the hash codes of
// contained objects to be calculated prematurely.
domainContent.setRepoId(parent.getName());
domainBase.setRepoId(parent.getName());
}
}
}
}
private static void fillAuxiliaryFieldsFromDomain(DomainHistory domainHistory) {
if (domainHistory.domainContent != null) {
domainHistory.nsHosts = nullToEmptyImmutableCopy(domainHistory.domainContent.nsHosts);
if (domainHistory.domainBase != null) {
domainHistory.nsHosts = nullToEmptyImmutableCopy(domainHistory.domainBase.nsHosts);
domainHistory.dsDataHistories =
nullToEmptyImmutableCopy(domainHistory.domainContent.getDsData()).stream()
nullToEmptyImmutableCopy(domainHistory.domainBase.getDsData()).stream()
.filter(dsData -> dsData.getDigest() != null && dsData.getDigest().length > 0)
.map(dsData -> DomainDsDataHistory.createFrom(domainHistory.id, dsData))
.collect(toImmutableSet());
domainHistory.gracePeriodHistories =
nullToEmptyImmutableCopy(domainHistory.domainContent.getGracePeriods()).stream()
nullToEmptyImmutableCopy(domainHistory.domainBase.getGracePeriods()).stream()
.map(gracePeriod -> GracePeriodHistory.createFrom(domainHistory.id, gracePeriod))
.collect(toImmutableSet());
} else {
@@ -372,35 +371,35 @@ public class DomainHistory extends HistoryEntry {
super(instance);
}
public Builder setDomain(@Nullable DomainContent domainContent) {
public Builder setDomain(@Nullable DomainBase domainBase) {
// Nullable for the sake of pre-Registry-3.0 history objects
if (domainContent == null) {
if (domainBase == null) {
return this;
}
// TODO(b/203609982): if actual type of domainContent is DomainBase, convert to DomainContent
// Note: a DomainHistory fetched by JPA has DomainContent in this field. Allowing DomainBase
// TODO(b/203609982): if actual type of domainBase is Domain, convert to DomainBase
// Note: a DomainHistory fetched by JPA has DomainBase in this field. Allowing Domain
// in the setter makes equality checks messy.
getInstance().domainContent = domainContent;
if (domainContent instanceof DomainBase) {
super.setParent(domainContent);
getInstance().domainBase = domainBase;
if (domainBase instanceof Domain) {
super.setParent(domainBase);
} else {
super.setParent(Key.create(DomainBase.class, domainContent.getRepoId()));
super.setParent(Key.create(Domain.class, domainBase.getRepoId()));
}
return this;
}
public Builder setDomainRepoId(String domainRepoId) {
getInstance().parent = Key.create(DomainBase.class, domainRepoId);
getInstance().parent = Key.create(Domain.class, domainRepoId);
return this;
}
@Override
public DomainHistory build() {
DomainHistory instance = super.build();
// TODO(b/171990736): Assert instance.domainContent is not null after database migration.
// Note that we cannot assert that instance.domainContent is not null here because this
// TODO(b/171990736): Assert instance.domainBase is not null after database migration.
// Note that we cannot assert that instance.domainBase is not null here because this
// builder is also used to convert legacy HistoryEntry objects to DomainHistory, when
// domainContent is not available.
// domainBase is not available.
fillAuxiliaryFieldsFromDomain(instance);
return instance;
}
@@ -37,8 +37,8 @@ import org.joda.time.DateTime;
/**
* A domain grace period with an expiration time.
*
* <p>When a grace period expires, it is lazily removed from the {@link DomainBase} the next time
* the resource is loaded from Datastore.
* <p>When a grace period expires, it is lazily removed from the {@link Domain} the next time the
* resource is loaded from Datastore.
*/
@Embed
@Entity
@@ -65,6 +65,7 @@ public class GracePeriodBase extends ImmutableObject implements UnsafeSerializab
// NB: Would @IgnoreSave(IfNull.class), but not allowed for @Embed collections.
@Access(AccessType.FIELD)
@Column(name = "billing_event_id")
@Ignore
VKey<BillingEvent.OneTime> billingEventOneTime = null;
/**
@@ -74,6 +75,7 @@ public class GracePeriodBase extends ImmutableObject implements UnsafeSerializab
// NB: Would @IgnoreSave(IfNull.class), but not allowed for @Embed collections.
@Access(AccessType.FIELD)
@Column(name = "billing_recurrence_id")
@Ignore
VKey<BillingEvent.Recurring> billingEventRecurring = null;
public long getGracePeriodId() {
@@ -168,6 +168,7 @@ public class AllocationToken extends BackupGroupRoot implements Buildable {
@Enumerated(EnumType.STRING)
@Column(name = "renewalPriceBehavior", nullable = false)
@Ignore
RenewalPriceBehavior renewalPriceBehavior = RenewalPriceBehavior.DEFAULT;
@Enumerated(EnumType.STRING)
@@ -22,8 +22,8 @@ import com.google.common.collect.ImmutableSet;
import google.registry.model.EppResource;
import google.registry.model.contact.ContactBase;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainContent;
import google.registry.model.host.HostBase;
import google.registry.model.host.HostResource;
import google.registry.model.translators.EnumToAttributeAdapter.EppEnum;
@@ -132,12 +132,12 @@ public enum StatusValue implements EppEnum {
ALL(
ContactBase.class,
ContactResource.class,
DomainContent.class,
DomainBase.class,
Domain.class,
HostBase.class,
HostResource.class),
NONE,
DOMAINS(DomainContent.class, DomainBase.class);
DOMAINS(DomainBase.class, Domain.class);
private final ImmutableSet<Class<? extends EppResource>> classes;
@@ -26,7 +26,7 @@ import com.googlecode.objectify.annotation.IgnoreSave;
import com.googlecode.objectify.annotation.Index;
import com.googlecode.objectify.condition.IfNull;
import google.registry.model.EppResource;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.transfer.TransferData;
import google.registry.persistence.VKey;
import java.net.InetAddress;
@@ -76,7 +76,7 @@ public class HostBase extends EppResource {
@Index
@IgnoreSave(IfNull.class)
@DoNotHydrate
VKey<DomainBase> superordinateDomain;
VKey<Domain> superordinateDomain;
/**
* The time that this resource was last transferred.
@@ -98,7 +98,7 @@ public class HostBase extends EppResource {
return fullyQualifiedHostName;
}
public VKey<DomainBase> getSuperordinateDomain() {
public VKey<Domain> getSuperordinateDomain() {
return superordinateDomain;
}
@@ -155,7 +155,7 @@ public class HostBase extends EppResource {
* {@link #superordinateDomain} field. Passing it as a parameter allows the caller to control
* the degree of consistency used to load it.
*/
public DateTime computeLastTransferTime(@Nullable DomainBase superordinateDomain) {
public DateTime computeLastTransferTime(@Nullable Domain superordinateDomain) {
if (!isSubordinate()) {
checkArgument(superordinateDomain == null);
return getLastTransferTime();
@@ -222,7 +222,7 @@ public class HostBase extends EppResource {
ImmutableSet.copyOf(difference(getInstance().getInetAddresses(), inetAddresses)));
}
public B setSuperordinateDomain(VKey<DomainBase> superordinateDomain) {
public B setSuperordinateDomain(VKey<Domain> superordinateDomain) {
getInstance().superordinateDomain = superordinateDomain;
return thisCastToDerived();
}
@@ -48,7 +48,7 @@ import google.registry.model.EppResource;
import google.registry.model.annotations.DeleteAfterMigration;
import google.registry.model.annotations.ReportedOn;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.host.HostResource;
import google.registry.persistence.VKey;
import google.registry.persistence.transaction.CriteriaQueryBuilder;
@@ -75,10 +75,10 @@ public abstract class ForeignKeyIndex<E extends EppResource> extends BackupGroup
@Entity
public static class ForeignKeyContactIndex extends ForeignKeyIndex<ContactResource> {}
/** The {@link ForeignKeyIndex} type for {@link DomainBase} entities. */
/** The {@link ForeignKeyIndex} type for {@link Domain} entities. */
@ReportedOn
@Entity
public static class ForeignKeyDomainIndex extends ForeignKeyIndex<DomainBase> {}
public static class ForeignKeyDomainIndex extends ForeignKeyIndex<Domain> {}
/** The {@link ForeignKeyIndex} type for {@link HostResource} entities. */
@ReportedOn
@@ -90,14 +90,14 @@ public abstract class ForeignKeyIndex<E extends EppResource> extends BackupGroup
RESOURCE_CLASS_TO_FKI_CLASS =
ImmutableBiMap.of(
ContactResource.class, ForeignKeyContactIndex.class,
DomainBase.class, ForeignKeyDomainIndex.class,
Domain.class, ForeignKeyDomainIndex.class,
HostResource.class, ForeignKeyHostIndex.class);
private static final ImmutableMap<Class<? extends EppResource>, String>
RESOURCE_CLASS_TO_FKI_PROPERTY =
ImmutableMap.of(
ContactResource.class, "contactId",
DomainBase.class, "fullyQualifiedDomainName",
Domain.class, "fullyQualifiedDomainName",
HostResource.class, "fullyQualifiedHostName");
@Id String foreignKey;
@@ -33,7 +33,7 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
* via Objectify.
*
* <p>All first class entities are represented as a resource class - {@link
* google.registry.model.domain.DomainBase}, {@link google.registry.model.host.HostResource}, {@link
* google.registry.model.domain.Domain}, {@link google.registry.model.host.HostResource}, {@link
* google.registry.model.contact.ContactResource}, and {@link
* google.registry.model.registrar.Registrar}. Resource objects are written in a single shared
* entity group per TLD. All commands that operate on those entities are grouped in a "Command"
@@ -35,7 +35,7 @@ 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.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.domain.DomainRenewData;
@@ -103,7 +103,7 @@ public abstract class PollMessage extends ImmutableObject
/** Indicates the type of entity the poll message is for. */
public enum Type {
DOMAIN(1L, DomainBase.class),
DOMAIN(1L, Domain.class),
CONTACT(2L, ContactResource.class),
HOST(3L, HostResource.class);
@@ -38,8 +38,8 @@ import google.registry.model.contact.ContactBase;
import google.registry.model.contact.ContactHistory;
import google.registry.model.contact.ContactHistory.ContactHistoryId;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainContent;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.domain.Period;
@@ -386,7 +386,7 @@ public class HistoryEntry extends ImmutableObject implements Buildable, UnsafeSe
String parentKind = getParent().getKind();
final HistoryEntry resultEntity;
// can't use a switch statement since we're calling getKind()
if (parentKind.equals(getKind(DomainBase.class))) {
if (parentKind.equals(getKind(Domain.class))) {
resultEntity =
new DomainHistory.Builder().copyFrom(this).setDomainRepoId(parent.getName()).build();
} else if (parentKind.equals(getKind(HostResource.class))) {
@@ -408,7 +408,7 @@ public class HistoryEntry extends ImmutableObject implements Buildable, UnsafeSe
long id = key.getId();
Key<EppResource> parent = key.getParent();
String parentKind = parent.getKind();
if (parentKind.equals(getKind(DomainBase.class))) {
if (parentKind.equals(getKind(Domain.class))) {
return VKey.create(
DomainHistory.class,
new DomainHistoryId(repoId, id),
@@ -537,8 +537,8 @@ public class HistoryEntry extends ImmutableObject implements Buildable, UnsafeSe
public static <E extends EppResource>
HistoryEntry.Builder<? extends HistoryEntry, ?> createBuilderForResource(E parent) {
if (parent instanceof DomainContent) {
return new DomainHistory.Builder().setDomain((DomainContent) parent);
if (parent instanceof DomainBase) {
return new DomainHistory.Builder().setDomain((DomainBase) parent);
} else if (parent instanceof ContactBase) {
return new ContactHistory.Builder().setContact((ContactBase) parent);
} else if (parent instanceof HostBase) {
@@ -27,7 +27,7 @@ import com.google.common.collect.Streams;
import google.registry.model.EppResource;
import google.registry.model.contact.ContactHistory;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.host.HostHistory;
import google.registry.model.host.HostResource;
@@ -53,7 +53,7 @@ public class HistoryEntryDao {
ImmutableMap.of(
ContactResource.class,
ContactHistory.class,
DomainBase.class,
Domain.class,
DomainHistory.class,
HostResource.class,
HostHistory.class);
@@ -66,7 +66,7 @@ public class ServerSecret extends CrossTldSingleton {
Optional<ServerSecret> secret = tm().loadSingleton(ServerSecret.class);
if (!secret.isPresent()) {
secret = Optional.of(create(UUID.randomUUID()));
tm().insertWithoutBackup(secret.get());
tm().insert(secret.get());
}
return secret.get();
});
@@ -56,7 +56,7 @@ public final class TmchCrl extends CrossTldSingleton {
tmchCrl.updated = jpaTm().getTransactionTime();
tmchCrl.crl = checkNotNull(crl, "crl");
tmchCrl.url = checkNotNull(url, "url");
jpaTm().transactNew(() -> jpaTm().putWithoutBackup(tmchCrl));
jpaTm().put(tmchCrl);
});
}
@@ -85,8 +85,8 @@ public class DomainTransferData extends TransferData<DomainTransferData.Builder>
* <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_event_id")
@Ignore
VKey<BillingEvent.OneTime> serverApproveBillingEvent;
/**
@@ -95,8 +95,8 @@ public class DomainTransferData extends TransferData<DomainTransferData.Builder>
* <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")
@Ignore
VKey<BillingEvent.Recurring> serverApproveAutorenewEvent;
/**
@@ -21,8 +21,6 @@ import com.google.appengine.api.datastore.Key;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import google.registry.persistence.BillingVKey.BillingEventVKey;
import google.registry.persistence.BillingVKey.BillingRecurrenceVKey;
import google.registry.persistence.DomainHistoryVKey;
import google.registry.persistence.EppHistoryVKey;
import java.lang.reflect.Constructor;
@@ -45,8 +43,7 @@ public class EppHistoryVKeyTranslatorFactory
// key, e.g. the map key for ContactPollMessageVKey is "ContactResource/HistoryEntry/PollMessage".
@VisibleForTesting
static final ImmutableMap<String, Class<? extends EppHistoryVKey>> kindPathToVKeyClass =
ImmutableSet.of(DomainHistoryVKey.class, BillingEventVKey.class, BillingRecurrenceVKey.class)
.stream()
ImmutableSet.of(DomainHistoryVKey.class).stream()
.collect(toImmutableMap(EppHistoryVKeyTranslatorFactory::getKindPath, identity()));
/**
@@ -1,125 +0,0 @@
// 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.persistence;
import com.googlecode.objectify.Key;
import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.OneTime;
import google.registry.model.billing.BillingEvent.Recurring;
import google.registry.model.domain.DomainBase;
import google.registry.model.reporting.HistoryEntry;
import java.io.Serializable;
import javax.annotation.Nullable;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.MappedSuperclass;
/** Base class for {@link BillingEvent}'s {@link VKey}. */
@MappedSuperclass
public abstract class BillingVKey<K> extends EppHistoryVKey<K, DomainBase> {
Long billingId;
// Hibernate requires a default constructor.
BillingVKey() {}
BillingVKey(String repoId, long historyRevisionId, long billingId) {
super(repoId, historyRevisionId);
this.billingId = billingId;
}
Key<HistoryEntry> createHistoryEntryKey() {
return Key.create(Key.create(DomainBase.class, repoId), HistoryEntry.class, historyRevisionId);
}
@Override
public Serializable createSqlKey() {
return billingId;
}
/** VKey class for {@link BillingEvent.OneTime} that belongs to a {@link DomainBase} entity. */
@Embeddable
@AttributeOverrides({
@AttributeOverride(name = "repoId", column = @Column(name = "billing_event_domain_repo_id")),
@AttributeOverride(
name = "historyRevisionId",
column = @Column(name = "billing_event_history_id")),
@AttributeOverride(name = "billingId", column = @Column(name = "billing_event_id"))
})
public static class BillingEventVKey extends BillingVKey<OneTime> {
// Hibernate requires this default constructor
private BillingEventVKey() {}
private BillingEventVKey(String repoId, long historyRevisionId, long billingEventId) {
super(repoId, historyRevisionId, billingEventId);
}
/** Creates a {@link BillingEventVKey} instance from the given {@link Key} instance. */
public static BillingEventVKey create(@Nullable Key<BillingEvent.OneTime> ofyKey) {
if (ofyKey == null) {
return null;
}
long billingEventId = ofyKey.getId();
long historyRevisionId = ofyKey.getParent().getId();
String repoId = ofyKey.getParent().getParent().getName();
return new BillingEventVKey(repoId, historyRevisionId, billingEventId);
}
/** Creates a {@link BillingEventVKey} instance from the given {@link VKey} instance. */
public static BillingEventVKey create(@Nullable VKey<BillingEvent.OneTime> vKey) {
return vKey == null ? null : new BillingEventVKey(null, 0, (Long) vKey.getSqlKey());
}
}
/** VKey class for {@link BillingEvent.Recurring} that belongs to a {@link DomainBase} entity. */
@Embeddable
@AttributeOverrides({
@AttributeOverride(
name = "repoId",
column = @Column(name = "billing_recurrence_domain_repo_id")),
@AttributeOverride(
name = "historyRevisionId",
column = @Column(name = "billing_recurrence_history_id")),
@AttributeOverride(name = "billingId", column = @Column(name = "billing_recurrence_id"))
})
public static class BillingRecurrenceVKey extends BillingVKey<Recurring> {
// Hibernate requires this default constructor
private BillingRecurrenceVKey() {}
private BillingRecurrenceVKey(String repoId, long historyRevisionId, long billingEventId) {
super(repoId, historyRevisionId, billingEventId);
}
/** Creates a {@link BillingRecurrenceVKey} instance from the given {@link Key} instance. */
public static BillingRecurrenceVKey create(@Nullable Key<BillingEvent.Recurring> ofyKey) {
if (ofyKey == null) {
return null;
}
long billingEventId = ofyKey.getId();
long historyRevisionId = ofyKey.getParent().getId();
String repoId = ofyKey.getParent().getParent().getName();
return new BillingRecurrenceVKey(repoId, historyRevisionId, billingEventId);
}
/** Creates a {@link BillingRecurrenceVKey} instance from the given {@link VKey} instance. */
public static BillingRecurrenceVKey create(@Nullable VKey<BillingEvent.Recurring> vKey) {
return vKey == null ? null : new BillingRecurrenceVKey(null, 0, (Long) vKey.getSqlKey());
}
}
}
@@ -17,16 +17,16 @@ package google.registry.persistence;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import com.googlecode.objectify.Key;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.reporting.HistoryEntry;
import java.io.Serializable;
import javax.persistence.Embeddable;
/** {@link VKey} for {@link HistoryEntry} which parent is {@link DomainBase}. */
/** {@link VKey} for {@link HistoryEntry} which parent is {@link Domain}. */
@Embeddable
public class DomainHistoryVKey extends EppHistoryVKey<HistoryEntry, DomainBase> {
public class DomainHistoryVKey extends EppHistoryVKey<HistoryEntry, Domain> {
// Hibernate requires a default constructor
private DomainHistoryVKey() {}
@@ -52,6 +52,6 @@ public class DomainHistoryVKey extends EppHistoryVKey<HistoryEntry, DomainBase>
return VKey.create(
DomainHistory.class,
createSqlKey(),
Key.create(Key.create(DomainBase.class, repoId), DomainHistory.class, historyRevisionId));
Key.create(Key.create(Domain.class, repoId), DomainHistory.class, historyRevisionId));
}
}

Some files were not shown because too many files have changed in this diff Show More