Generate basic schema for all of DomainBase (#246)

* Generate basic schema for all of DomainBase

Generate a basic schema for DomainBase and everything that is part of it.
This still isn't complete, in particular it lacks:

- Correct conversions for problematic types (e.g. DateTime, Key...)
- Schema generation for history records.
- Name translation.
This commit is contained in:
Michael Muller 2019-09-05 10:54:29 -04:00 committed by GitHub
parent 2967256766
commit f83a8a221b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 319 additions and 25 deletions

View file

@ -21,24 +21,26 @@ import com.googlecode.objectify.annotation.Embed;
import com.googlecode.objectify.annotation.Index;
import google.registry.model.ImmutableObject;
import google.registry.model.contact.ContactResource;
import javax.persistence.Id;
import javax.xml.bind.annotation.XmlEnumValue;
/**
* Persisted type for storing a domain's contact associations.
*
* <p>A contact association on a domain consists of the contact key and the contact "type", which is
* the designated role of this contact with respect to this domain. When converting to and from
* EPP XML, we use {@link ForeignKeyedDesignatedContact} to replace the contact's Datastore key
* with its foreign key, since that is what EPP exposes.
* the designated role of this contact with respect to this domain. When converting to and from EPP
* XML, we use {@link ForeignKeyedDesignatedContact} to replace the contact's Datastore key with its
* foreign key, since that is what EPP exposes.
*
* <p>Note one could in principle store contact foreign keys here in addition to keys, unlike the
* situation with hosts where client-side renames would make that data stale. However, we sometimes
* situation with hosts where client-side renames would make that data stale. However, we sometimes
* rename contacts internally ourselves, and it's easier to use the same model for both cases.
*
* @see <a href="http://tools.ietf.org/html/rfc5731#section-2.2">
* RFC 5731 - EPP Domain Name Mapping - Contact and Client Identifiers</a>
* @see <a href="http://tools.ietf.org/html/rfc5731#section-2.2">RFC 5731 - EPP Domain Name Mapping
* - Contact and Client Identifiers</a>
*/
@Embed
@javax.persistence.Entity
public class DesignatedContact extends ImmutableObject {
/**
@ -65,8 +67,7 @@ public class DesignatedContact extends ImmutableObject {
Type type;
@Index
Key<ContactResource> contact;
@Index @Id Key<ContactResource> contact;
public Type getType() {
return type;

View file

@ -19,6 +19,7 @@ import google.registry.model.eppcommon.AuthInfo;
/** A version of authInfo specifically for domains. */
@Embed
@javax.persistence.Embeddable
public class DomainAuthInfo extends AuthInfo {
public static DomainAuthInfo create(PasswordAuth pw) {
DomainAuthInfo instance = new DomainAuthInfo();

View file

@ -69,7 +69,11 @@ import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import javax.annotation.Nullable;
import javax.persistence.Transient;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Embedded;
import org.joda.time.DateTime;
import org.joda.time.Interval;
@ -118,17 +122,22 @@ public class DomainBase extends EppResource
String tld;
/** References to hosts that are the nameservers for the domain. */
@Index @Transient Set<Key<HostResource>> nsHosts;
@Index @ElementCollection Set<Key<HostResource>> nsHosts;
/**
* The union of the contacts visible via {@link #getContacts} and {@link #getRegistrant}.
*
* <p>These are stored in one field so that we can query across all contacts at once.
*/
@Transient Set<DesignatedContact> allContacts;
@ElementCollection Set<DesignatedContact> allContacts;
/** Authorization info (aka transfer secret) of the domain. */
@Transient DomainAuthInfo authInfo;
@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.
@ -136,13 +145,27 @@ public class DomainBase extends EppResource
* <p>This is {@literal @}XmlTransient because it needs to be returned under the "extension" tag
* of an info response rather than inside the "infData" tag.
*/
@Transient Set<DelegationSignerData> dsData;
@ElementCollection Set<DelegationSignerData> dsData;
/**
* The claims notice supplied when this application or domain was created, if there was one. It's
* {@literal @}XmlTransient because it's not returned in an info response.
*/
@IgnoreSave(IfNull.class) @Transient LaunchNotice launchNotice;
@IgnoreSave(IfNull.class)
@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.
@ -153,7 +176,7 @@ public class DomainBase extends EppResource
String idnTableName;
/** Fully qualified host names of this domain's active subordinate hosts. */
@Transient Set<String> subordinateHosts;
@ElementCollection Set<String> subordinateHosts;
/** When this domain's registration will expire. */
DateTime registrationExpirationTime;
@ -188,7 +211,7 @@ public class DomainBase extends EppResource
Key<PollMessage.Autorenew> autorenewPollMessage;
/** The unexpired grace periods for this domain (some of which may not be active yet). */
@Transient Set<GracePeriod> gracePeriods;
@ElementCollection Set<GracePeriod> gracePeriods;
/**
* The id of the signed mark that was used to create this domain in sunrise.
@ -199,7 +222,31 @@ public class DomainBase extends EppResource
String smdId;
/** Data about any pending or past transfers on this domain. */
@Transient TransferData transferData;
@Embedded
@AttributeOverrides({
@AttributeOverride(
name = "transferRequestTrid",
column = @Column(name = "transfer_data_request_trid")),
@AttributeOverride(
name = "transferPeriod",
column = @Column(name = "transfer_data_transfer_period")),
@AttributeOverride(
name = "transferredRegistrationExpirationTime",
column = @Column(name = "transfer_data_registration_expiration_time")),
@AttributeOverride(
name = "serverApproveEntities",
column = @Column(name = "transfer_data_server_approve_entities")),
@AttributeOverride(
name = "serverApproveBillingEvent",
column = @Column(name = "transfer_data_server_approve_billing_event")),
@AttributeOverride(
name = "serverApproveAutorenewEvent",
column = @Column(name = "transfer_data_server_approve_autorenrew_event")),
@AttributeOverride(
name = "serverApproveAutorenewPollMessage",
column = @Column(name = "transfer_data_server_approve_autorenrew_poll_message")),
})
TransferData transferData;
/**
* The time that this resource was last transferred.

View file

@ -19,21 +19,31 @@ import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.Embed;
import com.googlecode.objectify.annotation.Ignore;
import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingEvent;
import google.registry.model.domain.rgp.GracePeriodStatus;
import javax.annotation.Nullable;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
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 DomainBase} the next time
* the resource is loaded from Datastore.
*/
@Embed
@javax.persistence.Entity
public class GracePeriod extends ImmutableObject {
@javax.persistence.Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Ignore
/** Unique id required for hibernate representation. */
long id;
/** The type of grace period. */
GracePeriodStatus type;

View file

@ -22,6 +22,7 @@ import javax.xml.bind.annotation.XmlValue;
/** The "periodType" from {@link "http://tools.ietf.org/html/rfc5731"}. */
@Embed
@javax.persistence.Embeddable
public class Period extends ImmutableObject {
@XmlAttribute

View file

@ -28,6 +28,7 @@ import com.googlecode.objectify.annotation.IgnoreSave;
import com.googlecode.objectify.condition.IfNull;
import google.registry.model.ImmutableObject;
import java.util.Optional;
import javax.persistence.Embedded;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
@ -37,6 +38,7 @@ import org.joda.time.DateTime;
/** The claims notice id from the claims phase. */
@Embed
@XmlType(propOrder = {"noticeId", "expirationTime", "acceptedTime"})
@javax.persistence.Embeddable
public class LaunchNotice extends ImmutableObject {
/** An empty instance to use in place of null. */
@ -44,6 +46,7 @@ public class LaunchNotice extends ImmutableObject {
/** An id with a validator-id attribute. */
@Embed
@javax.persistence.Embeddable
public static class NoticeIdType extends ImmutableObject {
/**
@ -69,6 +72,7 @@ public class LaunchNotice extends ImmutableObject {
}
@XmlElement(name = "noticeID")
@Embedded
NoticeIdType noticeId;
@XmlElement(name = "notAfter")

View file

@ -30,12 +30,13 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
*/
@Embed
@XmlType(name = "dsData")
@javax.persistence.Entity
public class DelegationSignerData extends ImmutableObject {
private DelegationSignerData() {}
/** The identifier for this particular key in the domain. */
int keyTag;
@javax.persistence.Id int keyTag;
/**
* The algorithm used by this key.

View file

@ -16,6 +16,9 @@ package google.registry.model.eppcommon;
import com.googlecode.objectify.annotation.Embed;
import google.registry.model.ImmutableObject;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import javax.persistence.MappedSuperclass;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;
@ -30,9 +33,11 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
* <p>RFCs 5731 and 5732 define this almost identically up to the namespace.
*/
@XmlTransient
@Embeddable
@MappedSuperclass
public abstract class AuthInfo extends ImmutableObject {
protected PasswordAuth pw;
@Embedded protected PasswordAuth pw;
public PasswordAuth getPw() {
return pw;
@ -41,6 +46,7 @@ public abstract class AuthInfo extends ImmutableObject {
/** The "pwAuthInfoType" complex type. */
@Embed
@XmlType(namespace = "urn:ietf:params:xml:ns:eppcom-1.0")
@Embeddable
public static class PasswordAuth extends ImmutableObject {
@XmlValue
@XmlJavaTypeAdapter(NormalizedStringAdapter.class)

View file

@ -31,6 +31,7 @@ import javax.xml.bind.annotation.XmlType;
*/
@Embed
@XmlType(propOrder = {"clientTransactionId", "serverTransactionId"})
@javax.persistence.Embeddable
public class Trid extends ImmutableObject {
/** The server transaction id. */

View file

@ -16,12 +16,14 @@ package google.registry.model.transfer;
import google.registry.model.Buildable.GenericBuilder;
import google.registry.model.ImmutableObject;
import javax.persistence.MappedSuperclass;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
import org.joda.time.DateTime;
/** Fields common to {@link TransferData} and {@link TransferResponse}. */
@XmlTransient
@MappedSuperclass
public abstract class BaseTransferObject extends ImmutableObject {
/**
* The status of the current or last transfer. Can be null if never transferred. Note that we

View file

@ -31,20 +31,23 @@ import google.registry.model.eppcommon.Trid;
import google.registry.model.poll.PollMessage;
import java.util.Set;
import javax.annotation.Nullable;
import javax.persistence.ElementCollection;
import javax.persistence.Embedded;
import org.joda.time.DateTime;
/**
* Common transfer data for {@link EppResource} types. Only applies to domains and contacts;
* hosts are implicitly transferred with their superordinate domain.
* Common transfer data for {@link EppResource} types. Only applies to domains and contacts; hosts
* are implicitly transferred with their superordinate domain.
*/
@Embed
@Unindex
@javax.persistence.Embeddable
public class TransferData extends BaseTransferObject implements Buildable {
public static final TransferData EMPTY = new TransferData();
/** The transaction id of the most recent transfer request (or null if there never was one). */
Trid transferRequestTrid;
@Embedded Trid transferRequestTrid;
/**
* The period to extend the registration upon completion of the transfer.
@ -52,7 +55,7 @@ public class TransferData extends BaseTransferObject implements Buildable {
* <p>By default, domain transfers are for one year. This can be changed to zero by using the
* superuser EPP extension.
*/
Period transferPeriod = Period.create(1, Unit.YEARS);
@Embedded Period transferPeriod = Period.create(1, Unit.YEARS);
/**
* The registration expiration time resulting from the approval - speculative or actual - of the
@ -81,6 +84,7 @@ public class TransferData extends BaseTransferObject implements Buildable {
* be deleted.
*/
@IgnoreSave(IfNull.class)
@ElementCollection
Set<Key<? extends TransferServerApproveEntity>> serverApproveEntities;
/**

View file

@ -14,10 +14,21 @@
package google.registry.tools;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.annotations.VisibleForTesting;
import google.registry.model.domain.DesignatedContact;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.eppcommon.Trid;
import google.registry.model.transfer.BaseTransferObject;
import google.registry.model.transfer.TransferData;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
@ -25,6 +36,7 @@ import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.schema.TargetType;
import org.joda.time.Period;
import org.testcontainers.containers.PostgreSQLContainer;
/**
@ -122,12 +134,45 @@ public class GenerateSqlSchemaCommand implements Command {
MetadataSources metadata =
new MetadataSources(new StandardServiceRegistryBuilder().applySettings(settings).build());
metadata.addAnnotatedClass(BaseTransferObject.class);
metadata.addAnnotatedClass(DelegationSignerData.class);
metadata.addAnnotatedClass(DesignatedContact.class);
metadata.addAnnotatedClass(DomainBase.class);
metadata.addAnnotatedClass(GracePeriod.class);
metadata.addAnnotatedClass(Period.class);
metadata.addAnnotatedClass(TransferData.class);
metadata.addAnnotatedClass(Trid.class);
SchemaExport schemaExport = new SchemaExport();
schemaExport.setHaltOnError(true);
schemaExport.setFormat(true);
schemaExport.setDelimiter(";");
schemaExport.setOutputFile(outFile);
// Generate the copyright header (this file gets checked for copyright). The schema exporter
// appends to the existing file, so this has the additional desired effect of clearing any
// existing data in the file.
String copyright =
"-- Copyright 2019 The Nomulus Authors. All Rights Reserved.\n"
+ "--\n"
+ "-- Licensed under the Apache License, Version 2.0 (the \"License\");\n"
+ "-- you may not use this file except in compliance with the License.\n"
+ "-- You may obtain a copy of the License at\n"
+ "--\n"
+ "-- http://www.apache.org/licenses/LICENSE-2.0\n"
+ "--\n"
+ "-- Unless required by applicable law or agreed to in writing, software\n"
+ "-- distributed under the License is distributed on an \"AS IS\" BASIS,\n"
+ "-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
+ "-- See the License for the specific language governing permissions and\n"
+ "-- limitations under the License.\n";
try {
Files.write(Paths.get(outFile), copyright.getBytes(UTF_8));
} catch (IOException e) {
System.err.println("Error writing sql file: " + e);
e.printStackTrace();
System.exit(1);
}
schemaExport.createOnly(EnumSet.of(TargetType.SCRIPT), metadata.buildMetadata());
} finally {
if (postgresContainer != null) {

View file

@ -21,6 +21,14 @@
-->
<class>google.registry.model.domain.DomainBase</class>
<class>google.registry.schema.tmch.ClaimsList</class>
<class>google.registry.model.transfer.BaseTransferObject</class>
<class>google.registry.model.domain.secdns.DelegationSignerData</class>
<class>google.registry.model.domain.DesignatedContact</class>
<class>google.registry.model.domain.DomainBase</class>
<class>google.registry.model.domain.GracePeriod</class>
<class>org.joda.time.Period</class>
<class>google.registry.model.transfer.TransferData</class>
<class>google.registry.model.eppcommon.Trid</class>
<!-- TODO(weiminyu): check out application-layer validation. -->
<validation-mode>NONE</validation-mode>

View file

@ -0,0 +1,163 @@
-- Copyright 2019 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.
create table DelegationSignerData (
keyTag int4 not null,
algorithm int4 not null,
digest bytea,
digestType int4 not null,
primary key (keyTag)
);
create table DesignatedContact (
contact bytea not null,
type int4,
primary key (contact)
);
create table domain (
repoId varchar(255) not null,
creationClientId varchar(255),
currentSponsorClientId varchar(255),
deletionTime bytea,
lastEppUpdateClientId varchar(255),
lastEppUpdateTime bytea,
revisions bytea,
auth_info_repo_id varchar(255),
auth_info_value varchar(255),
autorenewBillingEvent bytea,
autorenewPollMessage bytea,
deletePollMessage bytea,
fullyQualifiedDomainName varchar(255),
idnTableName varchar(255),
lastTransferTime bytea,
launch_notice_accepted_time bytea,
launch_notice_expiration_time bytea,
launch_notice_tcn_id varchar(255),
launch_notice_validator_id varchar(255),
registrationExpirationTime bytea,
smdId varchar(255),
tld varchar(255),
transfer_data_server_approve_autorenrew_event bytea,
transfer_data_server_approve_autorenrew_poll_message bytea,
transfer_data_server_approve_billing_event bytea,
unit int4,
value int4,
clientTransactionId varchar(255),
serverTransactionId varchar(255),
transfer_data_registration_expiration_time bytea,
gainingClientId varchar(255),
losingClientId varchar(255),
pendingTransferExpirationTime bytea,
transferRequestTime bytea,
transferStatus int4,
primary key (repoId)
);
create table domain_DelegationSignerData (
DomainBase_repoId varchar(255) not null,
dsData_keyTag int4 not null,
primary key (DomainBase_repoId, dsData_keyTag)
);
create table domain_DesignatedContact (
DomainBase_repoId varchar(255) not null,
allContacts_contact bytea not null,
primary key (DomainBase_repoId, allContacts_contact)
);
create table domain_GracePeriod (
DomainBase_repoId varchar(255) not null,
gracePeriods_id int8 not null,
primary key (DomainBase_repoId, gracePeriods_id)
);
create table DomainBase_nsHosts (
DomainBase_repoId varchar(255) not null,
nsHosts bytea
);
create table DomainBase_serverApproveEntities (
DomainBase_repoId varchar(255) not null,
transfer_data_server_approve_entities bytea
);
create table DomainBase_subordinateHosts (
DomainBase_repoId varchar(255) not null,
subordinateHosts varchar(255)
);
create table GracePeriod (
id bigserial not null,
billingEventOneTime bytea,
billingEventRecurring bytea,
clientId varchar(255),
expirationTime bytea,
type int4,
primary key (id)
);
alter table domain_DelegationSignerData
add constraint UK_q2uk7gpqskey3t2w11w2o7x9f unique (dsData_keyTag);
alter table domain_DesignatedContact
add constraint UK_fyc0mfvebhatp6sq8dy4jdx4i unique (allContacts_contact);
alter table domain_GracePeriod
add constraint UK_74osb0s7br4x734ecpdk8caxx unique (gracePeriods_id);
alter table domain_DelegationSignerData
add constraint FK6p262lfef34yht2ok65rqfoiy
foreign key (dsData_keyTag)
references DelegationSignerData;
alter table domain_DelegationSignerData
add constraint FK922bmc01akk5mvypcdhtk3qqv
foreign key (DomainBase_repoId)
references domain;
alter table domain_DesignatedContact
add constraint FKdl5kay2hwlalnwcg12cpy12x9
foreign key (allContacts_contact)
references DesignatedContact;
alter table domain_DesignatedContact
add constraint FKb4nx8xr0n24f521y1i1cvr4f2
foreign key (DomainBase_repoId)
references domain;
alter table domain_GracePeriod
add constraint FKbw8o0nti4fevxu4xvu8unj726
foreign key (gracePeriods_id)
references GracePeriod;
alter table domain_GracePeriod
add constraint FKle4ms7cufyw4vgn5pn01vwwm7
foreign key (DomainBase_repoId)
references domain;
alter table DomainBase_nsHosts
add constraint FKblxt8vhg3yblt3grqxovoywwm
foreign key (DomainBase_repoId)
references domain;
alter table DomainBase_serverApproveEntities
add constraint FKbc3iicw0n8s9cj1lca142i7rc
foreign key (DomainBase_repoId)
references domain;
alter table DomainBase_subordinateHosts
add constraint FK3p6gm6lbx46s41hl9wfme77sr
foreign key (DomainBase_repoId)
references domain;