mirror of
https://github.com/google/nomulus.git
synced 2025-04-29 19:47:51 +02:00
Remove references to Objectify (#1846)
This is not a complete removal of ofy as we still a dependency on it (GaeUserIdConverter). But this PR removed it from a lot of places where it's no longer needed.
This commit is contained in:
parent
b578060c66
commit
cc451bb7dc
53 changed files with 82 additions and 921 deletions
|
@ -55,8 +55,6 @@ public class JpaDemoPipeline implements Serializable {
|
||||||
|
|
||||||
@ProcessElement
|
@ProcessElement
|
||||||
public void processElement() {
|
public void processElement() {
|
||||||
// AppEngineEnvironment is needed as long as JPA entity classes still depends
|
|
||||||
// on Objectify.
|
|
||||||
int result =
|
int result =
|
||||||
(Integer)
|
(Integer)
|
||||||
jpaTm()
|
jpaTm()
|
||||||
|
|
|
@ -64,7 +64,7 @@ public abstract class BillingEvent implements Serializable {
|
||||||
"amount",
|
"amount",
|
||||||
"flags");
|
"flags");
|
||||||
|
|
||||||
/** Returns the unique Objectify ID for the {@code OneTime} associated with this event. */
|
/** Returns the unique ID for the {@code OneTime} associated with this event. */
|
||||||
abstract long id();
|
abstract long id();
|
||||||
|
|
||||||
/** Returns the UTC DateTime this event becomes billable. */
|
/** Returns the UTC DateTime this event becomes billable. */
|
||||||
|
|
|
@ -29,12 +29,12 @@ import google.registry.flows.EppException.SyntaxErrorException;
|
||||||
import google.registry.flows.EppException.UnimplementedProtocolVersionException;
|
import google.registry.flows.EppException.UnimplementedProtocolVersionException;
|
||||||
import google.registry.flows.custom.EntityChanges;
|
import google.registry.flows.custom.EntityChanges;
|
||||||
import google.registry.model.EppResource;
|
import google.registry.model.EppResource;
|
||||||
|
import google.registry.model.adapters.CurrencyUnitAdapter.UnknownCurrencyException;
|
||||||
import google.registry.model.eppcommon.EppXmlTransformer;
|
import google.registry.model.eppcommon.EppXmlTransformer;
|
||||||
import google.registry.model.eppinput.EppInput.WrongProtocolVersionException;
|
import google.registry.model.eppinput.EppInput.WrongProtocolVersionException;
|
||||||
import google.registry.model.eppoutput.EppOutput;
|
import google.registry.model.eppoutput.EppOutput;
|
||||||
import google.registry.model.host.InetAddressAdapter.IpVersionMismatchException;
|
import google.registry.model.host.InetAddressAdapter.IpVersionMismatchException;
|
||||||
import google.registry.model.reporting.HistoryEntry.HistoryEntryId;
|
import google.registry.model.reporting.HistoryEntry.HistoryEntryId;
|
||||||
import google.registry.model.translators.CurrencyUnitAdapter.UnknownCurrencyException;
|
|
||||||
import google.registry.xml.XmlException;
|
import google.registry.xml.XmlException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ import static com.google.common.base.Preconditions.checkState;
|
||||||
import static google.registry.model.IdService.allocateId;
|
import static google.registry.model.IdService.allocateId;
|
||||||
import static google.registry.model.ModelUtils.getAllFields;
|
import static google.registry.model.ModelUtils.getAllFields;
|
||||||
|
|
||||||
import com.googlecode.objectify.annotation.Id;
|
|
||||||
import google.registry.model.annotations.OfyIdAllocation;
|
import google.registry.model.annotations.OfyIdAllocation;
|
||||||
import google.registry.util.TypeUtils.TypeInstantiator;
|
import google.registry.util.TypeUtils.TypeInstantiator;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
@ -56,14 +55,10 @@ public interface Buildable {
|
||||||
/** Build the instance. */
|
/** Build the instance. */
|
||||||
public S build() {
|
public S build() {
|
||||||
try {
|
try {
|
||||||
// If this object has a Long or long Objectify @Id field that is not set, set it now. For
|
// If this object has a Long or long @OfyIdAllocation field that is not set, set it now.
|
||||||
// any entity it has one and only one @Id field in its class hierarchy.
|
|
||||||
Field idField =
|
Field idField =
|
||||||
getAllFields(instance.getClass()).values().stream()
|
getAllFields(instance.getClass()).values().stream()
|
||||||
.filter(
|
.filter(field -> field.isAnnotationPresent(OfyIdAllocation.class))
|
||||||
field ->
|
|
||||||
field.isAnnotationPresent(Id.class)
|
|
||||||
|| field.isAnnotationPresent(OfyIdAllocation.class))
|
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
if (idField != null
|
if (idField != null
|
||||||
|
|
|
@ -21,8 +21,6 @@ import static java.util.stream.Collectors.toCollection;
|
||||||
import static java.util.stream.Collectors.toList;
|
import static java.util.stream.Collectors.toList;
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
import com.googlecode.objectify.Key;
|
|
||||||
import com.googlecode.objectify.annotation.Ignore;
|
|
||||||
import google.registry.persistence.VKey;
|
import google.registry.persistence.VKey;
|
||||||
import java.lang.annotation.Documented;
|
import java.lang.annotation.Documented;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
|
@ -76,7 +74,7 @@ public abstract class ImmutableObject implements Cloneable {
|
||||||
// Note: if this class is made to implement Serializable, this field must become 'transient' since
|
// Note: if this class is made to implement Serializable, this field must become 'transient' since
|
||||||
// hashing is not stable across executions. Also note that @XmlTransient is forbidden on transient
|
// hashing is not stable across executions. Also note that @XmlTransient is forbidden on transient
|
||||||
// fields and need to be removed if transient is added.
|
// fields and need to be removed if transient is added.
|
||||||
@Ignore @XmlTransient protected Integer hashCode;
|
@XmlTransient protected Integer hashCode;
|
||||||
|
|
||||||
private boolean equalsImmutableObject(ImmutableObject other) {
|
private boolean equalsImmutableObject(ImmutableObject other) {
|
||||||
return getClass().equals(other.getClass())
|
return getClass().equals(other.getClass())
|
||||||
|
@ -176,9 +174,6 @@ public abstract class ImmutableObject implements Cloneable {
|
||||||
|
|
||||||
/** Helper function to recursively hydrate an ImmutableObject. */
|
/** Helper function to recursively hydrate an ImmutableObject. */
|
||||||
private static Object hydrate(Object value) {
|
private static Object hydrate(Object value) {
|
||||||
if (value instanceof Key) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
if (value instanceof Map) {
|
if (value instanceof Map) {
|
||||||
return transformValues((Map<?, ?>) value, ImmutableObject::hydrate);
|
return transformValues((Map<?, ?>) value, ImmutableObject::hydrate);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,22 +25,13 @@ import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import com.google.common.collect.ImmutableSortedMap;
|
import com.google.common.collect.ImmutableSortedMap;
|
||||||
import com.google.common.collect.Streams;
|
import com.google.common.collect.Streams;
|
||||||
import com.googlecode.objectify.Key;
|
|
||||||
import com.googlecode.objectify.annotation.Id;
|
|
||||||
import com.googlecode.objectify.annotation.Ignore;
|
|
||||||
import com.googlecode.objectify.annotation.Parent;
|
|
||||||
import google.registry.persistence.VKey;
|
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.lang.reflect.ParameterizedType;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.AbstractList;
|
import java.util.AbstractList;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
@ -49,7 +40,6 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/** A collection of static methods that deal with reflection on model classes. */
|
/** A collection of static methods that deal with reflection on model classes. */
|
||||||
|
@ -86,84 +76,6 @@ public class ModelUtils {
|
||||||
return ALL_FIELDS_CACHE.get(clazz);
|
return ALL_FIELDS_CACHE.get(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return a string representing the persisted schema of a type or enum. */
|
|
||||||
static String getSchema(Class<?> clazz) {
|
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
|
||||||
Stream<?> body;
|
|
||||||
if (clazz.isEnum()) {
|
|
||||||
stringBuilder.append("enum ");
|
|
||||||
body = Arrays.stream(clazz.getEnumConstants());
|
|
||||||
} else {
|
|
||||||
stringBuilder.append("class ");
|
|
||||||
body =
|
|
||||||
getAllFields(clazz)
|
|
||||||
.values()
|
|
||||||
.stream()
|
|
||||||
.filter(field -> !field.isAnnotationPresent(Ignore.class))
|
|
||||||
.map(
|
|
||||||
field -> {
|
|
||||||
String annotation =
|
|
||||||
field.isAnnotationPresent(Id.class)
|
|
||||||
? "@Id "
|
|
||||||
: field.isAnnotationPresent(Parent.class) ? "@Parent " : "";
|
|
||||||
String type =
|
|
||||||
field.getType().isArray()
|
|
||||||
? field.getType().getComponentType().getName() + "[]"
|
|
||||||
: field.getGenericType().toString().replaceFirst("class ", "");
|
|
||||||
return String.format("%s%s %s", annotation, type, field.getName());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return stringBuilder
|
|
||||||
.append(clazz.getName())
|
|
||||||
.append(" {\n ")
|
|
||||||
.append(body.map(Object::toString).sorted().collect(Collectors.joining(";\n ")))
|
|
||||||
.append(";\n}")
|
|
||||||
.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the set of Class objects of all persisted fields. This includes the parameterized
|
|
||||||
* type(s) of any fields (if any).
|
|
||||||
*/
|
|
||||||
static Set<Class<?>> getPersistedFieldTypes(Class<?> clazz) {
|
|
||||||
ImmutableSet.Builder<Class<?>> builder = new ImmutableSet.Builder<>();
|
|
||||||
for (Field field : getAllFields(clazz).values()) {
|
|
||||||
// Skip fields that aren't persisted to Datastore.
|
|
||||||
if (field.isAnnotationPresent(Ignore.class)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the field's type is the same as the field's class object, then it's a non-parameterized
|
|
||||||
// type, and thus we just add it directly. We also don't bother looking at the parameterized
|
|
||||||
// types of Key and VKey objects, since they are just references to other objects and don't
|
|
||||||
// actually embed themselves in the persisted object anyway.
|
|
||||||
Class<?> fieldClazz = field.getType();
|
|
||||||
Type fieldType = field.getGenericType();
|
|
||||||
if (VKey.class.equals(fieldClazz)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
builder.add(fieldClazz);
|
|
||||||
if (fieldType.equals(fieldClazz) || Key.class.equals(clazz)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the field is a parameterized type, then also add the parameterized field.
|
|
||||||
if (fieldType instanceof ParameterizedType) {
|
|
||||||
ParameterizedType parameterizedType = (ParameterizedType) fieldType;
|
|
||||||
for (Type actualType : parameterizedType.getActualTypeArguments()) {
|
|
||||||
if (actualType instanceof Class<?>) {
|
|
||||||
builder.add((Class<?>) actualType);
|
|
||||||
} else {
|
|
||||||
// We intentionally ignore types that are parameterized on non-concrete types. In theory
|
|
||||||
// we could have collections embedded within collections, but Objectify does not allow
|
|
||||||
// that.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return builder.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Retrieves a field value via reflection. */
|
/** Retrieves a field value via reflection. */
|
||||||
static Object getFieldValue(Object instance, Field field) {
|
static Object getFieldValue(Object instance, Field field) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -29,7 +29,6 @@ import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.ImmutableSortedMap;
|
import com.google.common.collect.ImmutableSortedMap;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.google.common.collect.Streams;
|
import com.google.common.collect.Streams;
|
||||||
import com.googlecode.objectify.Key;
|
|
||||||
import google.registry.config.RegistryEnvironment;
|
import google.registry.config.RegistryEnvironment;
|
||||||
import google.registry.model.common.GaeUserIdConverter;
|
import google.registry.model.common.GaeUserIdConverter;
|
||||||
import google.registry.model.pricing.StaticPremiumListPricingEngine;
|
import google.registry.model.pricing.StaticPremiumListPricingEngine;
|
||||||
|
@ -199,9 +198,8 @@ public final class OteAccountBuilder {
|
||||||
*
|
*
|
||||||
* <p>Use this to set up registrar fields.
|
* <p>Use this to set up registrar fields.
|
||||||
*
|
*
|
||||||
* <p>NOTE: DO NOT change anything that would affect the {@link Key#create} result on Registrars.
|
* <p>NOTE: DO NOT change anything that would affect the result of {@link Registrar#createVKey()}
|
||||||
* If you want to make this function public, add a check that the Key.create on the registrars
|
* . If you want to make this function public, add a check that the value hasn't changed.
|
||||||
* hasn't changed.
|
|
||||||
*
|
*
|
||||||
* @param func a function setting the requested fields on Registrar Builders. Will be applied to
|
* @param func a function setting the requested fields on Registrar Builders. Will be applied to
|
||||||
* all the Registrars.
|
* all the Registrars.
|
||||||
|
|
|
@ -26,7 +26,6 @@ import com.google.common.collect.HashMultiset;
|
||||||
import com.google.common.collect.ImmutableCollection;
|
import com.google.common.collect.ImmutableCollection;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.Multiset;
|
import com.google.common.collect.Multiset;
|
||||||
import com.googlecode.objectify.Key;
|
|
||||||
import google.registry.model.domain.DomainCommand;
|
import google.registry.model.domain.DomainCommand;
|
||||||
import google.registry.model.domain.fee.FeeCreateCommandExtension;
|
import google.registry.model.domain.fee.FeeCreateCommandExtension;
|
||||||
import google.registry.model.domain.launch.LaunchCreateExtension;
|
import google.registry.model.domain.launch.LaunchCreateExtension;
|
||||||
|
@ -202,7 +201,7 @@ public class OteStats {
|
||||||
try {
|
try {
|
||||||
record(historyEntry);
|
record(historyEntry);
|
||||||
} catch (XmlException e) {
|
} catch (XmlException e) {
|
||||||
throw new RuntimeException("Couldn't parse history entry " + Key.create(historyEntry), e);
|
throw new RuntimeException("Couldn't parse history entry " + historyEntry.createVKey(), e);
|
||||||
}
|
}
|
||||||
// Break out early if all tests were passed.
|
// Break out early if all tests were passed.
|
||||||
if (wereAllTestsPassed()) {
|
if (wereAllTestsPassed()) {
|
||||||
|
|
|
@ -23,8 +23,8 @@ import java.io.Serializable;
|
||||||
* the migration. Note that only objects loaded from the SQL database need serialization support.
|
* the migration. Note that only objects loaded from the SQL database need serialization support.
|
||||||
*
|
*
|
||||||
* <p>All entities implementing this interface take advantage of the fact that all Java collection
|
* <p>All entities implementing this interface take advantage of the fact that all Java collection
|
||||||
* classes we use, either directly or indirectly, including those in Java libraries, Guava,
|
* classes we use, either directly or indirectly, including those in Java libraries, Guava, and
|
||||||
* Objectify, and Hibernate are {@code Serializable}.
|
* Hibernate are {@code Serializable}.
|
||||||
*
|
*
|
||||||
* <p>The {@code serialVersionUID} field has also been omitted in the implementing classes, since
|
* <p>The {@code serialVersionUID} field has also been omitted in the implementing classes, since
|
||||||
* they are not used for persistence.
|
* they are not used for persistence.
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
package google.registry.model;
|
package google.registry.model;
|
||||||
|
|
||||||
import com.googlecode.objectify.annotation.Ignore;
|
|
||||||
import google.registry.util.PreconditionsUtils;
|
import google.registry.util.PreconditionsUtils;
|
||||||
import javax.persistence.Access;
|
import javax.persistence.Access;
|
||||||
import javax.persistence.AccessType;
|
import javax.persistence.AccessType;
|
||||||
|
@ -39,7 +38,6 @@ public abstract class UpdateAutoTimestampEntity extends ImmutableObject
|
||||||
// Prevents subclasses from unexpectedly accessing as property (e.g., Host), which would
|
// Prevents subclasses from unexpectedly accessing as property (e.g., Host), which would
|
||||||
// require an unnecessary non-private setter method.
|
// require an unnecessary non-private setter method.
|
||||||
@Access(AccessType.FIELD)
|
@Access(AccessType.FIELD)
|
||||||
@Ignore
|
|
||||||
UpdateAutoTimestamp updateTimestamp = UpdateAutoTimestamp.create(null);
|
UpdateAutoTimestamp updateTimestamp = UpdateAutoTimestamp.create(null);
|
||||||
|
|
||||||
/** Get the {@link UpdateAutoTimestamp} for this entity. */
|
/** Get the {@link UpdateAutoTimestamp} for this entity. */
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package google.registry.model.translators;
|
package google.registry.model.adapters;
|
||||||
|
|
||||||
import static com.google.common.base.Strings.nullToEmpty;
|
import static com.google.common.base.Strings.nullToEmpty;
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package google.registry.model.translators;
|
package google.registry.model.adapters;
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlAttribute;
|
import javax.xml.bind.annotation.XmlAttribute;
|
||||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package google.registry.model.translators;
|
package google.registry.model.adapters;
|
||||||
|
|
||||||
import google.registry.model.eppcommon.StatusValue;
|
import google.registry.model.eppcommon.StatusValue;
|
||||||
|
|
|
@ -1,29 +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.annotations;
|
|
||||||
|
|
||||||
import com.googlecode.objectify.annotation.Entity;
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Annotation for an Objectify {@link Entity} to indicate that it should be exported to BigQuery.
|
|
||||||
*/
|
|
||||||
@DeleteAfterMigration
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Target({ElementType.TYPE})
|
|
||||||
public @interface ReportedOn {}
|
|
|
@ -29,7 +29,6 @@ import google.registry.model.Buildable;
|
||||||
import google.registry.model.ImmutableObject;
|
import google.registry.model.ImmutableObject;
|
||||||
import google.registry.model.UnsafeSerializable;
|
import google.registry.model.UnsafeSerializable;
|
||||||
import google.registry.model.annotations.OfyIdAllocation;
|
import google.registry.model.annotations.OfyIdAllocation;
|
||||||
import google.registry.model.annotations.ReportedOn;
|
|
||||||
import google.registry.model.common.TimeOfYear;
|
import google.registry.model.common.TimeOfYear;
|
||||||
import google.registry.model.domain.DomainHistory;
|
import google.registry.model.domain.DomainHistory;
|
||||||
import google.registry.model.domain.GracePeriod;
|
import google.registry.model.domain.GracePeriod;
|
||||||
|
@ -594,7 +593,6 @@ public abstract class BillingEvent extends ImmutableObject
|
||||||
* <p>This is implemented as a separate event rather than a bit on BillingEvent in order to
|
* <p>This is implemented as a separate event rather than a bit on BillingEvent in order to
|
||||||
* preserve the immutability of billing events.
|
* preserve the immutability of billing events.
|
||||||
*/
|
*/
|
||||||
@ReportedOn
|
|
||||||
@Entity(name = "BillingCancellation")
|
@Entity(name = "BillingCancellation")
|
||||||
@Table(
|
@Table(
|
||||||
indexes = {
|
indexes = {
|
||||||
|
|
|
@ -25,7 +25,6 @@ import static org.joda.time.DateTimeZone.UTC;
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
import com.google.common.collect.ContiguousSet;
|
import com.google.common.collect.ContiguousSet;
|
||||||
import com.google.common.collect.Range;
|
import com.google.common.collect.Range;
|
||||||
import com.googlecode.objectify.annotation.Index;
|
|
||||||
import google.registry.model.ImmutableObject;
|
import google.registry.model.ImmutableObject;
|
||||||
import google.registry.model.UnsafeSerializable;
|
import google.registry.model.UnsafeSerializable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -50,7 +49,6 @@ public class TimeOfYear extends ImmutableObject implements UnsafeSerializable {
|
||||||
* The time as "month day millis" with all fields left-padded with zeroes so that lexographic
|
* The time as "month day millis" with all fields left-padded with zeroes so that lexographic
|
||||||
* sorting will do the right thing.
|
* sorting will do the right thing.
|
||||||
*/
|
*/
|
||||||
@Index
|
|
||||||
String timeString;
|
String timeString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -241,8 +241,8 @@ public class ContactBase extends EppResource
|
||||||
* Postal info for the contact.
|
* Postal info for the contact.
|
||||||
*
|
*
|
||||||
* <p>The XML marshalling expects the {@link PostalInfo} objects in a list, but we can't actually
|
* <p>The XML marshalling expects the {@link PostalInfo} objects in a list, but we can't actually
|
||||||
* persist them to Datastore that way because Objectify can't handle collections of embedded
|
* persist them directly due to legacy reasons (Objectify can't handle collections of embedded
|
||||||
* objects that themselves contain collections, and there's a list of streets inside. This method
|
* objects that themselves contain collections, and there's a list of streets inside). This method
|
||||||
* transforms the persisted format to the XML format for marshalling.
|
* transforms the persisted format to the XML format for marshalling.
|
||||||
*/
|
*/
|
||||||
@XmlElement(name = "postalInfo")
|
@XmlElement(name = "postalInfo")
|
||||||
|
|
|
@ -16,7 +16,6 @@ package google.registry.model.domain;
|
||||||
|
|
||||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||||
|
|
||||||
import com.googlecode.objectify.annotation.Ignore;
|
|
||||||
import google.registry.model.ImmutableObject;
|
import google.registry.model.ImmutableObject;
|
||||||
import google.registry.model.UnsafeSerializable;
|
import google.registry.model.UnsafeSerializable;
|
||||||
import google.registry.model.contact.Contact;
|
import google.registry.model.contact.Contact;
|
||||||
|
@ -69,7 +68,7 @@ public class DesignatedContact extends ImmutableObject implements UnsafeSerializ
|
||||||
|
|
||||||
Type type;
|
Type type;
|
||||||
|
|
||||||
@Ignore VKey<Contact> contactVKey;
|
VKey<Contact> contactVKey;
|
||||||
|
|
||||||
public Type getType() {
|
public Type getType() {
|
||||||
return type;
|
return type;
|
||||||
|
|
|
@ -18,7 +18,6 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.googlecode.objectify.annotation.Ignore;
|
|
||||||
import google.registry.model.EppResource;
|
import google.registry.model.EppResource;
|
||||||
import google.registry.model.domain.GracePeriod.GracePeriodHistory;
|
import google.registry.model.domain.GracePeriod.GracePeriodHistory;
|
||||||
import google.registry.model.domain.secdns.DomainDsData;
|
import google.registry.model.domain.secdns.DomainDsData;
|
||||||
|
@ -115,7 +114,6 @@ public class DomainHistory extends HistoryEntry {
|
||||||
updatable = false)
|
updatable = false)
|
||||||
})
|
})
|
||||||
// HashSet rather than ImmutableSet so that Hibernate can fill them out lazily on request
|
// HashSet rather than ImmutableSet so that Hibernate can fill them out lazily on request
|
||||||
@Ignore
|
|
||||||
Set<DomainDsDataHistory> dsDataHistories = new HashSet<>();
|
Set<DomainDsDataHistory> dsDataHistories = new HashSet<>();
|
||||||
|
|
||||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
|
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
@XmlJavaTypeAdapter(CurrencyUnitAdapter.class)
|
@XmlJavaTypeAdapter(CurrencyUnitAdapter.class)
|
||||||
package google.registry.model.domain.fee06;
|
package google.registry.model.domain.fee06;
|
||||||
|
|
||||||
import google.registry.model.translators.CurrencyUnitAdapter;
|
import google.registry.model.adapters.CurrencyUnitAdapter;
|
||||||
import javax.xml.bind.annotation.XmlAccessType;
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
import javax.xml.bind.annotation.XmlNs;
|
import javax.xml.bind.annotation.XmlNs;
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
@XmlJavaTypeAdapter(CurrencyUnitAdapter.class)
|
@XmlJavaTypeAdapter(CurrencyUnitAdapter.class)
|
||||||
package google.registry.model.domain.fee11;
|
package google.registry.model.domain.fee11;
|
||||||
|
|
||||||
import google.registry.model.translators.CurrencyUnitAdapter;
|
import google.registry.model.adapters.CurrencyUnitAdapter;
|
||||||
import javax.xml.bind.annotation.XmlAccessType;
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
import javax.xml.bind.annotation.XmlNs;
|
import javax.xml.bind.annotation.XmlNs;
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
@XmlJavaTypeAdapter(UtcDateTimeAdapter.class)})
|
@XmlJavaTypeAdapter(UtcDateTimeAdapter.class)})
|
||||||
package google.registry.model.domain.fee12;
|
package google.registry.model.domain.fee12;
|
||||||
|
|
||||||
import google.registry.model.translators.CurrencyUnitAdapter;
|
import google.registry.model.adapters.CurrencyUnitAdapter;
|
||||||
import google.registry.xml.UtcDateTimeAdapter;
|
import google.registry.xml.UtcDateTimeAdapter;
|
||||||
import javax.xml.bind.annotation.XmlAccessType;
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
|
|
@ -17,8 +17,8 @@ package google.registry.model.domain.rgp;
|
||||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import google.registry.model.translators.EnumToAttributeAdapter;
|
import google.registry.model.adapters.EnumToAttributeAdapter;
|
||||||
import google.registry.model.translators.EnumToAttributeAdapter.EppEnum;
|
import google.registry.model.adapters.EnumToAttributeAdapter.EppEnum;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.xml.bind.annotation.XmlAttribute;
|
import javax.xml.bind.annotation.XmlAttribute;
|
||||||
|
|
|
@ -20,14 +20,14 @@ import static com.google.common.base.Strings.nullToEmpty;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import google.registry.model.EppResource;
|
import google.registry.model.EppResource;
|
||||||
|
import google.registry.model.adapters.EnumToAttributeAdapter.EppEnum;
|
||||||
|
import google.registry.model.adapters.StatusValueAdapter;
|
||||||
import google.registry.model.contact.Contact;
|
import google.registry.model.contact.Contact;
|
||||||
import google.registry.model.contact.ContactBase;
|
import google.registry.model.contact.ContactBase;
|
||||||
import google.registry.model.domain.Domain;
|
import google.registry.model.domain.Domain;
|
||||||
import google.registry.model.domain.DomainBase;
|
import google.registry.model.domain.DomainBase;
|
||||||
import google.registry.model.host.Host;
|
import google.registry.model.host.Host;
|
||||||
import google.registry.model.host.HostBase;
|
import google.registry.model.host.HostBase;
|
||||||
import google.registry.model.translators.EnumToAttributeAdapter.EppEnum;
|
|
||||||
import google.registry.model.translators.StatusValueAdapter;
|
|
||||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -14,26 +14,26 @@
|
||||||
|
|
||||||
package google.registry.model.host;
|
package google.registry.model.host;
|
||||||
|
|
||||||
import com.googlecode.objectify.annotation.Entity;
|
|
||||||
import google.registry.model.EppResource.ForeignKeyedEppResource;
|
import google.registry.model.EppResource.ForeignKeyedEppResource;
|
||||||
import google.registry.model.annotations.ExternalMessagingName;
|
import google.registry.model.annotations.ExternalMessagingName;
|
||||||
import google.registry.model.annotations.ReportedOn;
|
|
||||||
import google.registry.persistence.VKey;
|
import google.registry.persistence.VKey;
|
||||||
import google.registry.persistence.WithVKey;
|
import google.registry.persistence.WithVKey;
|
||||||
import javax.persistence.Access;
|
import javax.persistence.Access;
|
||||||
import javax.persistence.AccessType;
|
import javax.persistence.AccessType;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Index;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A persistable Host resource including mutable and non-mutable fields.
|
* A persistable Host resource including mutable and non-mutable fields.
|
||||||
*
|
*
|
||||||
* <p>The {@link javax.persistence.Id} of the Host is the repoId.
|
* <p>The {@link javax.persistence.Id} of the Host is the repoId.
|
||||||
*/
|
*/
|
||||||
@ReportedOn
|
@Entity(name = "Host")
|
||||||
@Entity
|
@Table(
|
||||||
@javax.persistence.Entity(name = "Host")
|
|
||||||
@javax.persistence.Table(
|
|
||||||
name = "Host",
|
name = "Host",
|
||||||
/**
|
/*
|
||||||
* A gin index defined on the inet_addresses field ({@link HostBase#inetAddresses} cannot be
|
* A gin index defined on the inet_addresses field ({@link HostBase#inetAddresses} cannot be
|
||||||
* declared here because JPA/Hibernate does not support index type specification. As a result,
|
* declared here because JPA/Hibernate does not support index type specification. As a result,
|
||||||
* the hibernate-generated schema (which is for reference only) does not have this index.
|
* the hibernate-generated schema (which is for reference only) does not have this index.
|
||||||
|
@ -45,10 +45,10 @@ import javax.persistence.AccessType;
|
||||||
* doing either.
|
* doing either.
|
||||||
*/
|
*/
|
||||||
indexes = {
|
indexes = {
|
||||||
@javax.persistence.Index(columnList = "hostName"),
|
@Index(columnList = "hostName"),
|
||||||
@javax.persistence.Index(columnList = "creationTime"),
|
@Index(columnList = "creationTime"),
|
||||||
@javax.persistence.Index(columnList = "deletionTime"),
|
@Index(columnList = "deletionTime"),
|
||||||
@javax.persistence.Index(columnList = "currentSponsorRegistrarId")
|
@Index(columnList = "currentSponsorRegistrarId")
|
||||||
})
|
})
|
||||||
@ExternalMessagingName("host")
|
@ExternalMessagingName("host")
|
||||||
@WithVKey(String.class)
|
@WithVKey(String.class)
|
||||||
|
@ -56,7 +56,7 @@ import javax.persistence.AccessType;
|
||||||
public class Host extends HostBase implements ForeignKeyedEppResource {
|
public class Host extends HostBase implements ForeignKeyedEppResource {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@javax.persistence.Id
|
@Id
|
||||||
@Access(AccessType.PROPERTY) // to tell it to use the non-default property-as-ID
|
@Access(AccessType.PROPERTY) // to tell it to use the non-default property-as-ID
|
||||||
public String getRepoId() {
|
public String getRepoId() {
|
||||||
return super.getRepoId();
|
return super.getRepoId();
|
||||||
|
|
|
@ -21,27 +21,17 @@ import static google.registry.util.TypeUtils.hasAnnotation;
|
||||||
|
|
||||||
import com.google.appengine.api.datastore.AsyncDatastoreService;
|
import com.google.appengine.api.datastore.AsyncDatastoreService;
|
||||||
import com.google.appengine.api.datastore.DatastoreServiceConfig;
|
import com.google.appengine.api.datastore.DatastoreServiceConfig;
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.Streams;
|
import com.google.common.collect.Streams;
|
||||||
import com.googlecode.objectify.Key;
|
import com.googlecode.objectify.Key;
|
||||||
import com.googlecode.objectify.Objectify;
|
|
||||||
import com.googlecode.objectify.ObjectifyFactory;
|
import com.googlecode.objectify.ObjectifyFactory;
|
||||||
import com.googlecode.objectify.annotation.Entity;
|
import com.googlecode.objectify.annotation.Entity;
|
||||||
import com.googlecode.objectify.annotation.EntitySubclass;
|
import com.googlecode.objectify.annotation.EntitySubclass;
|
||||||
import com.googlecode.objectify.impl.translate.TranslatorFactory;
|
|
||||||
import com.googlecode.objectify.impl.translate.opt.joda.MoneyStringTranslatorFactory;
|
|
||||||
import google.registry.config.RegistryEnvironment;
|
import google.registry.config.RegistryEnvironment;
|
||||||
import google.registry.model.Buildable;
|
import google.registry.model.Buildable;
|
||||||
import google.registry.model.ImmutableObject;
|
import google.registry.model.ImmutableObject;
|
||||||
import google.registry.model.annotations.DeleteAfterMigration;
|
import google.registry.model.annotations.DeleteAfterMigration;
|
||||||
import google.registry.model.common.GaeUserIdConverter;
|
import google.registry.model.common.GaeUserIdConverter;
|
||||||
import google.registry.model.translators.BloomFilterOfStringTranslatorFactory;
|
|
||||||
import google.registry.model.translators.CidrAddressBlockTranslatorFactory;
|
|
||||||
import google.registry.model.translators.CurrencyUnitTranslatorFactory;
|
|
||||||
import google.registry.model.translators.DurationTranslatorFactory;
|
|
||||||
import google.registry.model.translators.InetAddressTranslatorFactory;
|
|
||||||
import google.registry.model.translators.ReadableInstantUtcTranslatorFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An instance of Ofy, obtained via {@code #auditedOfy()}, should be used to access all persistable
|
* An instance of Ofy, obtained via {@code #auditedOfy()}, should be used to access all persistable
|
||||||
|
@ -86,11 +76,6 @@ public class ObjectifyService {
|
||||||
// The "false" argument means that we are not using the v5-style Objectify embedded entities.
|
// The "false" argument means that we are not using the v5-style Objectify embedded entities.
|
||||||
com.googlecode.objectify.ObjectifyService.setFactory(
|
com.googlecode.objectify.ObjectifyService.setFactory(
|
||||||
new ObjectifyFactory(false) {
|
new ObjectifyFactory(false) {
|
||||||
@Override
|
|
||||||
public Objectify begin() {
|
|
||||||
return new SessionKeyExposingObjectify(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AsyncDatastoreService createRawAsyncDatastoreService(
|
protected AsyncDatastoreService createRawAsyncDatastoreService(
|
||||||
DatastoreServiceConfig cfg) {
|
DatastoreServiceConfig cfg) {
|
||||||
|
@ -103,26 +88,9 @@ public class ObjectifyService {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Translators must be registered before any entities can be registered.
|
|
||||||
registerTranslators();
|
|
||||||
registerEntityClasses(ImmutableSet.of(GaeUserIdConverter.class));
|
registerEntityClasses(ImmutableSet.of(GaeUserIdConverter.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Register translators that allow less common types to be stored directly in Datastore. */
|
|
||||||
private static void registerTranslators() {
|
|
||||||
for (TranslatorFactory<?> translatorFactory :
|
|
||||||
ImmutableList.of(
|
|
||||||
new BloomFilterOfStringTranslatorFactory(),
|
|
||||||
new CidrAddressBlockTranslatorFactory(),
|
|
||||||
new CurrencyUnitTranslatorFactory(),
|
|
||||||
new DurationTranslatorFactory(),
|
|
||||||
new InetAddressTranslatorFactory(),
|
|
||||||
new MoneyStringTranslatorFactory(),
|
|
||||||
new ReadableInstantUtcTranslatorFactory())) {
|
|
||||||
factory().getTranslators().add(translatorFactory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Register classes that can be persisted via Objectify as Datastore entities. */
|
/** Register classes that can be persisted via Objectify as Datastore entities. */
|
||||||
private static void registerEntityClasses(
|
private static void registerEntityClasses(
|
||||||
ImmutableSet<Class<? extends ImmutableObject>> entityClasses) {
|
ImmutableSet<Class<? extends ImmutableObject>> entityClasses) {
|
||||||
|
|
|
@ -25,7 +25,6 @@ import com.google.appengine.api.datastore.DatastoreTimeoutException;
|
||||||
import com.google.appengine.api.taskqueue.TransientFailureException;
|
import com.google.appengine.api.taskqueue.TransientFailureException;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import com.google.common.collect.Streams;
|
import com.google.common.collect.Streams;
|
||||||
import com.google.common.flogger.FluentLogger;
|
import com.google.common.flogger.FluentLogger;
|
||||||
import com.googlecode.objectify.Key;
|
import com.googlecode.objectify.Key;
|
||||||
|
@ -97,16 +96,6 @@ public class Ofy {
|
||||||
return ofy().factory();
|
return ofy().factory();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns keys read by Objectify during this transaction.
|
|
||||||
*
|
|
||||||
* <p>This won't include the keys of asynchronous save and delete operations that haven't been
|
|
||||||
* reaped.
|
|
||||||
*/
|
|
||||||
public ImmutableSet<Key<?>> getSessionKeys() {
|
|
||||||
return ((SessionKeyExposingObjectify) ofy()).getSessionKeys();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Clears the session cache. */
|
/** Clears the session cache. */
|
||||||
public void clearSessionCache() {
|
public void clearSessionCache() {
|
||||||
ofy().clear();
|
ofy().clear();
|
||||||
|
@ -272,7 +261,6 @@ public class Ofy {
|
||||||
});
|
});
|
||||||
return work.getResult();
|
return work.getResult();
|
||||||
} catch (TransientFailureException
|
} catch (TransientFailureException
|
||||||
| TimestampInversionException
|
|
||||||
| DatastoreTimeoutException
|
| DatastoreTimeoutException
|
||||||
| DatastoreFailureException e) {
|
| DatastoreFailureException e) {
|
||||||
// TransientFailureExceptions come from task queues and always mean nothing committed.
|
// TransientFailureExceptions come from task queues and always mean nothing committed.
|
||||||
|
|
|
@ -1,35 +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.ofy;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import com.googlecode.objectify.Key;
|
|
||||||
import com.googlecode.objectify.ObjectifyFactory;
|
|
||||||
import com.googlecode.objectify.impl.ObjectifyImpl;
|
|
||||||
import google.registry.model.annotations.DeleteAfterMigration;
|
|
||||||
|
|
||||||
/** Registry-specific Objectify subclass that exposes the keys used in the current session. */
|
|
||||||
@DeleteAfterMigration
|
|
||||||
public class SessionKeyExposingObjectify extends ObjectifyImpl<SessionKeyExposingObjectify> {
|
|
||||||
|
|
||||||
public SessionKeyExposingObjectify(ObjectifyFactory factory) {
|
|
||||||
super(factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Expose the protected method that provides the keys read, saved or deleted in a session. */
|
|
||||||
ImmutableSet<Key<?>> getSessionKeys() {
|
|
||||||
return ImmutableSet.copyOf(getSession().keys());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,62 +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.ofy;
|
|
||||||
|
|
||||||
import com.googlecode.objectify.Key;
|
|
||||||
import com.googlecode.objectify.Objectify;
|
|
||||||
import google.registry.model.UpdateAutoTimestampEntity;
|
|
||||||
import google.registry.model.annotations.DeleteAfterMigration;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Map;
|
|
||||||
import org.joda.time.DateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception when trying to write to Datastore with a timestamp that is inconsistent with a partial
|
|
||||||
* ordering on transactions that touch the same entities.
|
|
||||||
*/
|
|
||||||
@DeleteAfterMigration
|
|
||||||
class TimestampInversionException extends RuntimeException {
|
|
||||||
|
|
||||||
static String getFileAndLine(StackTraceElement callsite) {
|
|
||||||
return callsite.getFileName() + ":" + callsite.getLineNumber();
|
|
||||||
}
|
|
||||||
|
|
||||||
TimestampInversionException(
|
|
||||||
DateTime transactionTime, Map<Key<UpdateAutoTimestampEntity>, DateTime> problematicRoots) {
|
|
||||||
this(transactionTime, "entities rooted under:\n" + problematicRoots);
|
|
||||||
}
|
|
||||||
|
|
||||||
TimestampInversionException(DateTime transactionTime, DateTime updateTimestamp) {
|
|
||||||
this(transactionTime, String.format("update timestamp (%s)", updateTimestamp));
|
|
||||||
}
|
|
||||||
|
|
||||||
private TimestampInversionException(DateTime transactionTime, String problem) {
|
|
||||||
super(
|
|
||||||
String.format(
|
|
||||||
"Timestamp inversion between transaction time (%s) and %s\n%s",
|
|
||||||
transactionTime,
|
|
||||||
problem,
|
|
||||||
getFileAndLine(
|
|
||||||
Arrays.stream(new Exception().getStackTrace())
|
|
||||||
.filter(
|
|
||||||
element ->
|
|
||||||
!element
|
|
||||||
.getClassName()
|
|
||||||
.startsWith(Objectify.class.getPackage().getName())
|
|
||||||
&& !element.getClassName().startsWith(Ofy.class.getName()))
|
|
||||||
.findFirst()
|
|
||||||
.get())));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -29,22 +29,21 @@ import javax.xml.bind.annotation.XmlSchema;
|
||||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This package defines all entities which are managed via EPP XML and persisted to the Datastore
|
* This package defines all entities which are managed via EPP XML and persisted to SQL via
|
||||||
* via Objectify.
|
* Hibernate.
|
||||||
*
|
*
|
||||||
* <p>All first class entities are represented as a resource class - {@link
|
* <p>All first class entities are represented as a resource class - {@link
|
||||||
* google.registry.model.domain.Domain}, {@link google.registry.model.host.Host}, {@link
|
* google.registry.model.domain.Domain}, {@link google.registry.model.host.Host}, {@link
|
||||||
* google.registry.model.contact.Contact}, and {@link
|
* google.registry.model.contact.Contact}, and {@link
|
||||||
* google.registry.model.registrar.Registrar}. Resource objects are written in a single shared
|
* google.registry.model.registrar.Registrar}. All commands that operate on those entities are
|
||||||
* entity group per TLD. All commands that operate on those entities are grouped in a "Command"
|
* grouped in a "Command" class- {@link google.registry.model.domain.DomainCommand}, {@link
|
||||||
* class- {@link google.registry.model.domain.DomainCommand}, {@link
|
|
||||||
* google.registry.model.host.HostCommand}, {@link google.registry.model.contact.ContactCommand}.
|
* google.registry.model.host.HostCommand}, {@link google.registry.model.contact.ContactCommand}.
|
||||||
* The Resource does double duty as both the persisted representation and as the XML-marshallable
|
* The Resource does double duty as both the persisted representation and as the XML-marshallable
|
||||||
* object returned in respond to Info commands.
|
* object returned in respond to Info commands.
|
||||||
*
|
*
|
||||||
* <p>Command classes are never persisted, and the Objectify annotations on the Create and Update
|
* <p>Command classes are never persisted.
|
||||||
* classes are purely for the benefit of the derived Resource classes that inherit from them.
|
* Whenever a command that mutates the model is executed, a {@link
|
||||||
* Whenever a command that mutates the model is executed, a HistoryEvent is stored with the affected
|
* google.registry.reporting.HistoryEvent} is stored with the affected Resource as an embedded
|
||||||
* Resource as its Datastore parent. All history entries have an indexed modification time field so
|
* field. All history entries have an indexed modification time field so that the history can be
|
||||||
* that the history can be read in chronological order.
|
* read in chronological order.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -35,7 +35,6 @@ import google.registry.model.ImmutableObject;
|
||||||
import google.registry.model.JsonMapBuilder;
|
import google.registry.model.JsonMapBuilder;
|
||||||
import google.registry.model.Jsonifiable;
|
import google.registry.model.Jsonifiable;
|
||||||
import google.registry.model.UnsafeSerializable;
|
import google.registry.model.UnsafeSerializable;
|
||||||
import google.registry.model.annotations.ReportedOn;
|
|
||||||
import google.registry.model.registrar.RegistrarPoc.RegistrarPocId;
|
import google.registry.model.registrar.RegistrarPoc.RegistrarPocId;
|
||||||
import google.registry.persistence.VKey;
|
import google.registry.persistence.VKey;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
@ -57,7 +56,6 @@ import javax.persistence.Table;
|
||||||
* *MUST* also modify the persisted Registrar entity with {@link Registrar#contactsRequireSyncing}
|
* *MUST* also modify the persisted Registrar entity with {@link Registrar#contactsRequireSyncing}
|
||||||
* set to true.
|
* set to true.
|
||||||
*/
|
*/
|
||||||
@ReportedOn
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(indexes = {@Index(columnList = "gaeUserId", name = "registrarpoc_gae_user_id_idx")})
|
@Table(indexes = {@Index(columnList = "gaeUserId", name = "registrarpoc_gae_user_id_idx")})
|
||||||
@IdClass(RegistrarPocId.class)
|
@IdClass(RegistrarPocId.class)
|
||||||
|
|
|
@ -23,8 +23,6 @@ import com.google.common.base.Splitter;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.hash.BloomFilter;
|
import com.google.common.hash.BloomFilter;
|
||||||
import google.registry.model.Buildable;
|
import google.registry.model.Buildable;
|
||||||
import google.registry.model.ImmutableObject;
|
|
||||||
import google.registry.model.annotations.ReportedOn;
|
|
||||||
import google.registry.model.tld.Registry;
|
import google.registry.model.tld.Registry;
|
||||||
import google.registry.model.tld.label.PremiumList.PremiumEntry;
|
import google.registry.model.tld.label.PremiumList.PremiumEntry;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
@ -35,6 +33,7 @@ import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.Index;
|
import javax.persistence.Index;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
import javax.persistence.Transient;
|
import javax.persistence.Transient;
|
||||||
|
@ -49,8 +48,7 @@ import org.joda.money.Money;
|
||||||
* succeeds, we will end up with having two exact same premium lists that differ only by revisionId.
|
* succeeds, we will end up with having two exact same premium lists that differ only by revisionId.
|
||||||
* This is fine though, because we only use the list with the highest revisionId.
|
* This is fine though, because we only use the list with the highest revisionId.
|
||||||
*/
|
*/
|
||||||
@ReportedOn
|
@Entity
|
||||||
@javax.persistence.Entity
|
|
||||||
@Table(indexes = {@Index(columnList = "name", name = "premiumlist_name_idx")})
|
@Table(indexes = {@Index(columnList = "name", name = "premiumlist_name_idx")})
|
||||||
public final class PremiumList extends BaseDomainLabelList<BigDecimal, PremiumEntry> {
|
public final class PremiumList extends BaseDomainLabelList<BigDecimal, PremiumEntry> {
|
||||||
|
|
||||||
|
@ -64,7 +62,7 @@ public final class PremiumList extends BaseDomainLabelList<BigDecimal, PremiumEn
|
||||||
* from the immutability contract so we can modify it after construction and we have to handle the
|
* from the immutability contract so we can modify it after construction and we have to handle the
|
||||||
* database processing on our own so we can detach it after load.
|
* database processing on our own so we can detach it after load.
|
||||||
*/
|
*/
|
||||||
@ImmutableObject.Insignificant @Transient ImmutableMap<String, BigDecimal> labelsToPrices;
|
@Insignificant @Transient ImmutableMap<String, BigDecimal> labelsToPrices;
|
||||||
|
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
BloomFilter<String> bloomFilter;
|
BloomFilter<String> bloomFilter;
|
||||||
|
@ -116,11 +114,11 @@ public final class PremiumList extends BaseDomainLabelList<BigDecimal, PremiumEn
|
||||||
* A premium list entry entity, persisted to Cloud SQL. Each instance represents the price of a
|
* A premium list entry entity, persisted to Cloud SQL. Each instance represents the price of a
|
||||||
* single label on a given TLD.
|
* single label on a given TLD.
|
||||||
*/
|
*/
|
||||||
@javax.persistence.Entity(name = "PremiumEntry")
|
@Entity(name = "PremiumEntry")
|
||||||
public static class PremiumEntry extends DomainLabelEntry<BigDecimal, PremiumList.PremiumEntry>
|
public static class PremiumEntry extends DomainLabelEntry<BigDecimal, PremiumList.PremiumEntry>
|
||||||
implements Buildable, Serializable {
|
implements Buildable, Serializable {
|
||||||
|
|
||||||
@ImmutableObject.Insignificant @javax.persistence.Id Long revisionId;
|
@Insignificant @javax.persistence.Id Long revisionId;
|
||||||
|
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
BigDecimal price;
|
BigDecimal price;
|
||||||
|
|
|
@ -29,11 +29,7 @@ import org.joda.time.DateTime;
|
||||||
@XmlTransient
|
@XmlTransient
|
||||||
@MappedSuperclass
|
@MappedSuperclass
|
||||||
public abstract class BaseTransferObject extends ImmutableObject implements UnsafeSerializable {
|
public abstract class BaseTransferObject extends ImmutableObject implements UnsafeSerializable {
|
||||||
/**
|
/** The status of the current or last transfer. Can be null if never transferred. */
|
||||||
* The status of the current or last transfer. Can be null if never transferred. Note that we
|
|
||||||
* leave IgnoreSave off this field so that we can ensure that TransferData loaded from Objectify
|
|
||||||
* will always be non-null.
|
|
||||||
*/
|
|
||||||
@XmlElement(name = "trStatus")
|
@XmlElement(name = "trStatus")
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
TransferStatus transferStatus;
|
TransferStatus transferStatus;
|
||||||
|
|
|
@ -1,61 +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.translators;
|
|
||||||
|
|
||||||
import com.googlecode.objectify.impl.Path;
|
|
||||||
import com.googlecode.objectify.impl.Property;
|
|
||||||
import com.googlecode.objectify.impl.translate.CreateContext;
|
|
||||||
import com.googlecode.objectify.impl.translate.LoadContext;
|
|
||||||
import com.googlecode.objectify.impl.translate.SaveContext;
|
|
||||||
import com.googlecode.objectify.impl.translate.ValueTranslator;
|
|
||||||
import com.googlecode.objectify.impl.translate.ValueTranslatorFactory;
|
|
||||||
import google.registry.util.TypeUtils.TypeInstantiator;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
|
|
||||||
/** Common boilerplate for translator factories. */
|
|
||||||
public abstract class AbstractSimpleTranslatorFactory<P, D> extends ValueTranslatorFactory<P, D> {
|
|
||||||
|
|
||||||
public AbstractSimpleTranslatorFactory(Class<P> clazz) {
|
|
||||||
super(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected final ValueTranslator<P, D> createSafe(
|
|
||||||
Path path, Property property, Type type, CreateContext ctx) {
|
|
||||||
return new ValueTranslator<P, D>(path, new TypeInstantiator<D>(getClass()){}.getExactType()) {
|
|
||||||
|
|
||||||
SimpleTranslator<P, D> simpleTranslator = createTranslator();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected P loadValue(D datastoreValue, LoadContext ctx) {
|
|
||||||
return simpleTranslator.loadValue(datastoreValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected D saveValue(P pojoValue, SaveContext ctx) {
|
|
||||||
return simpleTranslator.saveValue(pojoValue);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Translator with reduced boilerplate. */
|
|
||||||
interface SimpleTranslator<P, D> {
|
|
||||||
P loadValue(D datastoreValue);
|
|
||||||
|
|
||||||
D saveValue(P pojoValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract SimpleTranslator<P, D> createTranslator();
|
|
||||||
}
|
|
|
@ -1,90 +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.translators;
|
|
||||||
|
|
||||||
import static com.google.common.hash.Funnels.unencodedCharsFunnel;
|
|
||||||
import static com.googlecode.objectify.repackaged.gentyref.GenericTypeReflector.erase;
|
|
||||||
import static com.googlecode.objectify.repackaged.gentyref.GenericTypeReflector.getTypeParameter;
|
|
||||||
|
|
||||||
import com.google.appengine.api.datastore.Blob;
|
|
||||||
import com.google.common.hash.BloomFilter;
|
|
||||||
import com.google.common.hash.Funnel;
|
|
||||||
import com.google.common.reflect.TypeToken;
|
|
||||||
import com.googlecode.objectify.impl.Path;
|
|
||||||
import com.googlecode.objectify.impl.Property;
|
|
||||||
import com.googlecode.objectify.impl.translate.CreateContext;
|
|
||||||
import com.googlecode.objectify.impl.translate.LoadContext;
|
|
||||||
import com.googlecode.objectify.impl.translate.SaveContext;
|
|
||||||
import com.googlecode.objectify.impl.translate.Translator;
|
|
||||||
import com.googlecode.objectify.impl.translate.TranslatorFactory;
|
|
||||||
import com.googlecode.objectify.impl.translate.ValueTranslator;
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
/** Stores CharSequence {@link BloomFilter}s as blobs. */
|
|
||||||
public class BloomFilterOfStringTranslatorFactory
|
|
||||||
implements TranslatorFactory<BloomFilter<String>> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Translator<BloomFilter<String>> create(
|
|
||||||
Path path, Property property, Type type, CreateContext ctx) {
|
|
||||||
if (!BloomFilter.class.equals(erase(type))) {
|
|
||||||
return null; // Skip me and try to find another matching translator
|
|
||||||
}
|
|
||||||
Type fieldBloomFilterType = getTypeParameter(type, BloomFilter.class.getTypeParameters()[0]);
|
|
||||||
if (fieldBloomFilterType == null) {
|
|
||||||
return null; // No type information is available
|
|
||||||
}
|
|
||||||
if (!TypeToken.of(String.class).getType().equals(fieldBloomFilterType)) {
|
|
||||||
return null; // We can only handle BloomFilters of CharSequences
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ValueTranslator<BloomFilter<String>, Blob>(path, Blob.class) {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
protected BloomFilter<String> loadValue(Blob value, LoadContext ctx) {
|
|
||||||
if (value == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
Funnel<String> castedFunnel = (Funnel<String>) (Funnel<?>) unencodedCharsFunnel();
|
|
||||||
return BloomFilter.readFrom(new ByteArrayInputStream(value.getBytes()), castedFunnel);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalStateException("Error loading Bloom filter data", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
protected Blob saveValue(BloomFilter<String> value, SaveContext ctx) {
|
|
||||||
if (value == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
||||||
try {
|
|
||||||
value.writeTo(bos);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalStateException("Error saving Bloom filter data", e);
|
|
||||||
}
|
|
||||||
return new Blob(bos.toByteArray());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,40 +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.translators;
|
|
||||||
|
|
||||||
import google.registry.util.CidrAddressBlock;
|
|
||||||
|
|
||||||
/** Stores {@link CidrAddressBlock} as a canonicalized string. */
|
|
||||||
public class CidrAddressBlockTranslatorFactory
|
|
||||||
extends AbstractSimpleTranslatorFactory<CidrAddressBlock, String> {
|
|
||||||
|
|
||||||
public CidrAddressBlockTranslatorFactory() {
|
|
||||||
super(CidrAddressBlock.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
SimpleTranslator<CidrAddressBlock, String> createTranslator() {
|
|
||||||
return new SimpleTranslator<CidrAddressBlock, String>(){
|
|
||||||
@Override
|
|
||||||
public CidrAddressBlock loadValue(String datastoreValue) {
|
|
||||||
return CidrAddressBlock.create(datastoreValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String saveValue(CidrAddressBlock pojoValue) {
|
|
||||||
return pojoValue.toString();
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,40 +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.translators;
|
|
||||||
|
|
||||||
import org.joda.money.CurrencyUnit;
|
|
||||||
|
|
||||||
/** Stores {@link CurrencyUnit} as a canonicalized string. */
|
|
||||||
public class CurrencyUnitTranslatorFactory
|
|
||||||
extends AbstractSimpleTranslatorFactory<CurrencyUnit, String> {
|
|
||||||
|
|
||||||
public CurrencyUnitTranslatorFactory() {
|
|
||||||
super(CurrencyUnit.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
SimpleTranslator<CurrencyUnit, String> createTranslator() {
|
|
||||||
return new SimpleTranslator<CurrencyUnit, String>(){
|
|
||||||
@Override
|
|
||||||
public CurrencyUnit loadValue(String datastoreValue) {
|
|
||||||
return CurrencyUnit.of(datastoreValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String saveValue(CurrencyUnit pojoValue) {
|
|
||||||
return pojoValue.toString();
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +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.translators;
|
|
||||||
|
|
||||||
import org.joda.time.Duration;
|
|
||||||
|
|
||||||
/** Stores {@link Duration} as a canonicalized string. */
|
|
||||||
public class DurationTranslatorFactory extends AbstractSimpleTranslatorFactory<Duration, String> {
|
|
||||||
|
|
||||||
public DurationTranslatorFactory() {
|
|
||||||
super(Duration.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected SimpleTranslator<Duration, String> createTranslator() {
|
|
||||||
return new SimpleTranslator<Duration, String>() {
|
|
||||||
@Override
|
|
||||||
public Duration loadValue(String datastoreValue) {
|
|
||||||
return Duration.parse(datastoreValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String saveValue(Duration pojoValue) {
|
|
||||||
return pojoValue.toString();
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,165 +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.translators;
|
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
|
||||||
import static com.google.common.base.Preconditions.checkState;
|
|
||||||
import static com.googlecode.objectify.repackaged.gentyref.GenericTypeReflector.erase;
|
|
||||||
import static com.googlecode.objectify.repackaged.gentyref.GenericTypeReflector.getTypeParameter;
|
|
||||||
import static google.registry.util.CollectionUtils.nullToEmpty;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableSortedMap;
|
|
||||||
import com.google.common.collect.Ordering;
|
|
||||||
import com.google.common.reflect.TypeToken;
|
|
||||||
import com.googlecode.objectify.impl.Node;
|
|
||||||
import com.googlecode.objectify.impl.Path;
|
|
||||||
import com.googlecode.objectify.impl.Property;
|
|
||||||
import com.googlecode.objectify.impl.translate.CreateContext;
|
|
||||||
import com.googlecode.objectify.impl.translate.ListNodeTranslator;
|
|
||||||
import com.googlecode.objectify.impl.translate.LoadContext;
|
|
||||||
import com.googlecode.objectify.impl.translate.SaveContext;
|
|
||||||
import com.googlecode.objectify.impl.translate.SkipException;
|
|
||||||
import com.googlecode.objectify.impl.translate.Translator;
|
|
||||||
import com.googlecode.objectify.impl.translate.TranslatorFactory;
|
|
||||||
import com.googlecode.objectify.impl.translate.TranslatorRegistry;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.Map;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract Objectify translator for {@link ImmutableSortedMap} fields.
|
|
||||||
*
|
|
||||||
* <p>This class should be extended for each set of concrete key/value types you wish to support.
|
|
||||||
* This translator will only apply to {@code ImmutableSortedMap} model fields that have precicely
|
|
||||||
* the same type parameters you specified.
|
|
||||||
*
|
|
||||||
* <p>This translator serves a similar purpose to
|
|
||||||
* {@link com.googlecode.objectify.impl.translate.MapifyTranslatorFactory @Mapify}. Except this
|
|
||||||
* maintains perfect immutability of the field value. Subclasses may override the
|
|
||||||
* {@link #transformBeforeSave(ImmutableSortedMap)} methods to perform mutation on a per-concrete
|
|
||||||
* type basis. This abstraction is also more readable than {@code @Mapify} because it shifts the
|
|
||||||
* boilerplate into translator magic, rather than convoluting model data structures.
|
|
||||||
*
|
|
||||||
* <h3>Entity Data Layout</h3>
|
|
||||||
*
|
|
||||||
* <p>For example, if you had an {@code ImmutableSortedMap<String, String>} on a field named
|
|
||||||
* {@code field}, then this would look like:<pre> {@code
|
|
||||||
*
|
|
||||||
* field.key: key1 -> key2
|
|
||||||
* field.value: value1 -> value2}</pre>
|
|
||||||
*
|
|
||||||
* <p>If you had an {@code ImmutableSortedMap<String, EmbeddedClass>} on a field named
|
|
||||||
* {@code field}, where {@code EmbeddedClass} defines two {@code foo} and {@code bar} fields, then
|
|
||||||
* the embedded properties might look like:<pre> {@code
|
|
||||||
*
|
|
||||||
* field.key: key1 -> key2
|
|
||||||
* field.value.foo: foo1 -> foo2
|
|
||||||
* field.value.bar: bar1 -> bar2}</pre>
|
|
||||||
*
|
|
||||||
* @param <K> key type for sorted map which must be {@link Comparable}
|
|
||||||
* @param <V> value type for sorted map
|
|
||||||
*/
|
|
||||||
abstract class ImmutableSortedMapTranslatorFactory<K extends Comparable<? super K>, V>
|
|
||||||
implements TranslatorFactory<ImmutableSortedMap<K, V>> {
|
|
||||||
|
|
||||||
private final TypeToken<K> keyType = new TypeToken<K>(getClass()) {};
|
|
||||||
private final TypeToken<V> valueType = new TypeToken<V>(getClass()) {};
|
|
||||||
private final String keyProperty;
|
|
||||||
private final String valueProperty;
|
|
||||||
|
|
||||||
ImmutableSortedMapTranslatorFactory() {
|
|
||||||
this("key", "value");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Constructs a instance that's compatible with models migrated from {@code @Mapify}. */
|
|
||||||
ImmutableSortedMapTranslatorFactory(String keyProperty, String valueProperty) {
|
|
||||||
this.keyProperty = checkNotNull(keyProperty);
|
|
||||||
this.valueProperty = checkNotNull(valueProperty);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Allows for changing the field data structure before it's written to the raw entity object. */
|
|
||||||
ImmutableSortedMap<K, V> transformBeforeSave(ImmutableSortedMap<K, V> map) {
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final Translator<ImmutableSortedMap<K, V>>
|
|
||||||
create(Path path, Property property, Type type, CreateContext ctx) {
|
|
||||||
if (!ImmutableSortedMap.class.equals(erase(type))) {
|
|
||||||
return null; // skip me and try to find another matching translator
|
|
||||||
}
|
|
||||||
Type fieldKeyType = getTypeParameter(type, ImmutableSortedMap.class.getTypeParameters()[0]);
|
|
||||||
Type fieldValueType = getTypeParameter(type, ImmutableSortedMap.class.getTypeParameters()[1]);
|
|
||||||
if (fieldKeyType == null || fieldValueType == null) {
|
|
||||||
return null; // no type information is available
|
|
||||||
}
|
|
||||||
if (!keyType.isSupertypeOf(fieldKeyType) || !valueType.isSupertypeOf(fieldValueType)) {
|
|
||||||
return null; // this ImmutableSortedMap does not have the same concrete component types
|
|
||||||
}
|
|
||||||
ctx.enterCollection(path);
|
|
||||||
ctx.enterEmbed(path);
|
|
||||||
try {
|
|
||||||
// The component types can also be translated by Objectify!
|
|
||||||
TranslatorRegistry translators = ctx.getFactory().getTranslators();
|
|
||||||
final Translator<K> keyTranslator =
|
|
||||||
translators.create(path.extend(keyProperty), property, fieldKeyType, ctx);
|
|
||||||
final Translator<V> valueTranslator =
|
|
||||||
translators.create(path.extend(valueProperty), property, fieldValueType, ctx);
|
|
||||||
return new ListNodeTranslator<ImmutableSortedMap<K, V>>() {
|
|
||||||
@Override
|
|
||||||
protected ImmutableSortedMap<K, V> loadList(Node node, LoadContext ctx) {
|
|
||||||
ImmutableSortedMap.Builder<K, V> map =
|
|
||||||
new ImmutableSortedMap.Builder<>(Ordering.natural());
|
|
||||||
for (Node child : node) {
|
|
||||||
try {
|
|
||||||
map.put(keyTranslator.load(child.get(keyProperty), ctx),
|
|
||||||
valueTranslator.load(child.get(valueProperty), ctx));
|
|
||||||
} catch (SkipException e) {
|
|
||||||
// no problem, just skip that one
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return map.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Node saveList(
|
|
||||||
@Nullable ImmutableSortedMap<K, V> mapFromPojo,
|
|
||||||
Path path,
|
|
||||||
boolean index,
|
|
||||||
SaveContext ctx) {
|
|
||||||
checkState(!index, "At path %s: Index not allowed", path);
|
|
||||||
ImmutableSortedMap<K, V> mapToSave = transformBeforeSave(
|
|
||||||
ImmutableSortedMap.copyOfSorted(nullToEmpty(mapFromPojo)));
|
|
||||||
if (mapToSave.isEmpty()) {
|
|
||||||
throw new SkipException(); // Datastore doesn't store empty lists
|
|
||||||
}
|
|
||||||
Node node = new Node(path);
|
|
||||||
for (Map.Entry<K, V> entry : mapToSave.entrySet()) {
|
|
||||||
Node item = new Node(path);
|
|
||||||
item.put(keyProperty,
|
|
||||||
keyTranslator.save(entry.getKey(), path.extend(keyProperty), index, ctx));
|
|
||||||
item.put(valueProperty,
|
|
||||||
valueTranslator.save(entry.getValue(), path.extend(valueProperty), index, ctx));
|
|
||||||
node.addToList(item);
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} finally {
|
|
||||||
ctx.exitEmbed();
|
|
||||||
ctx.exitCollection();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +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.translators;
|
|
||||||
|
|
||||||
import com.google.common.net.InetAddresses;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
|
|
||||||
/** Stores {@link InetAddress} as a canonicalized string. */
|
|
||||||
public class InetAddressTranslatorFactory
|
|
||||||
extends AbstractSimpleTranslatorFactory<InetAddress, String> {
|
|
||||||
|
|
||||||
public InetAddressTranslatorFactory() {
|
|
||||||
super(InetAddress.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
SimpleTranslator<InetAddress, String> createTranslator() {
|
|
||||||
return new SimpleTranslator<InetAddress, String>() {
|
|
||||||
@Override
|
|
||||||
public InetAddress loadValue(String datastoreValue) {
|
|
||||||
return InetAddresses.forString(datastoreValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String saveValue(InetAddress pojoValue) {
|
|
||||||
return pojoValue.getHostAddress();
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,65 +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.translators;
|
|
||||||
|
|
||||||
import com.googlecode.objectify.impl.Path;
|
|
||||||
import com.googlecode.objectify.impl.Property;
|
|
||||||
import com.googlecode.objectify.impl.TypeUtils;
|
|
||||||
import com.googlecode.objectify.impl.translate.CreateContext;
|
|
||||||
import com.googlecode.objectify.impl.translate.LoadContext;
|
|
||||||
import com.googlecode.objectify.impl.translate.SaveContext;
|
|
||||||
import com.googlecode.objectify.impl.translate.ValueTranslator;
|
|
||||||
import com.googlecode.objectify.impl.translate.ValueTranslatorFactory;
|
|
||||||
import com.googlecode.objectify.repackaged.gentyref.GenericTypeReflector;
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.Date;
|
|
||||||
import org.joda.time.DateTimeZone;
|
|
||||||
import org.joda.time.ReadableInstant;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores Joda {@link ReadableInstant} types ({@code DateTime}, etc) as a {@link java.util.Date}.
|
|
||||||
*
|
|
||||||
* <p>This is a fork of the {@code ReadableInstantTranslatorFactory} that comes bundled with
|
|
||||||
* Objectify. The original reifies a {@link ReadableInstant} using the machine's local time
|
|
||||||
* zone. This version always uses UTC.
|
|
||||||
*/
|
|
||||||
public class ReadableInstantUtcTranslatorFactory
|
|
||||||
extends ValueTranslatorFactory<ReadableInstant, Date> {
|
|
||||||
|
|
||||||
public ReadableInstantUtcTranslatorFactory() {
|
|
||||||
super(ReadableInstant.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ValueTranslator<ReadableInstant, Date> createSafe(
|
|
||||||
Path path, Property property, Type type, CreateContext ctx) {
|
|
||||||
final Class<?> clazz = GenericTypeReflector.erase(type);
|
|
||||||
|
|
||||||
return new ValueTranslator<ReadableInstant, Date>(path, Date.class) {
|
|
||||||
@Override
|
|
||||||
protected ReadableInstant loadValue(Date value, LoadContext ctx) {
|
|
||||||
// All the Joda instants have a constructor that will take a Date and timezone.
|
|
||||||
Constructor<?> ctor = TypeUtils.getConstructor(clazz, Object.class, DateTimeZone.class);
|
|
||||||
return (ReadableInstant) TypeUtils.newInstance(ctor, value, DateTimeZone.UTC);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Date saveValue(ReadableInstant value, SaveContext ctx) {
|
|
||||||
return value.toInstant().toDate();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -27,7 +27,7 @@ import javax.annotation.Nullable;
|
||||||
import javax.persistence.criteria.CriteriaBuilder;
|
import javax.persistence.criteria.CriteriaBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates queries that can be used both for objectify and JPA.
|
* Creates queries that can be used JPA.
|
||||||
*
|
*
|
||||||
* <p>Example usage:
|
* <p>Example usage:
|
||||||
*
|
*
|
||||||
|
|
|
@ -53,8 +53,8 @@ import javax.inject.Inject;
|
||||||
* <p>All commands and responses conform to the RDAP spec as defined in RFCs 7480 through 7485.
|
* <p>All commands and responses conform to the RDAP spec as defined in RFCs 7480 through 7485.
|
||||||
*
|
*
|
||||||
* <p>The RDAP specification lumps contacts and registrars together and calls them "entities", which
|
* <p>The RDAP specification lumps contacts and registrars together and calls them "entities", which
|
||||||
* is confusing for us, because "entity" means something else in Objectify. But here, when we use
|
* is confusing for us, because "entity" means something else in SQL. But here, when we use the
|
||||||
* the term, it means either a contact or registrar. When searching for entities, we always start by
|
* term, it means either a contact or registrar. When searching for entities, we always start by
|
||||||
* returning all matching contacts, and after that all matching registrars.
|
* returning all matching contacts, and after that all matching registrars.
|
||||||
*
|
*
|
||||||
* <p>There are two ways to search for entities: by full name (for contacts, the search name, for
|
* <p>There are two ways to search for entities: by full name (for contacts, the search name, for
|
||||||
|
|
|
@ -18,7 +18,6 @@ import static com.google.common.base.Verify.verify;
|
||||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
|
|
||||||
import com.google.common.flogger.FluentLogger;
|
import com.google.common.flogger.FluentLogger;
|
||||||
import com.googlecode.objectify.Key;
|
|
||||||
import google.registry.model.ImmutableObject;
|
import google.registry.model.ImmutableObject;
|
||||||
import google.registry.model.contact.Contact;
|
import google.registry.model.contact.Contact;
|
||||||
import google.registry.model.domain.Domain;
|
import google.registry.model.domain.Domain;
|
||||||
|
@ -164,10 +163,12 @@ public final class RdeMarshaller implements Serializable {
|
||||||
try {
|
try {
|
||||||
xml = marshal(element);
|
xml = marshal(element);
|
||||||
} catch (MarshalException e) {
|
} catch (MarshalException e) {
|
||||||
error = String.format("RDE XML schema validation failed: %s\n%s%s\n",
|
error =
|
||||||
Key.create(resource),
|
String.format(
|
||||||
e.getLinkedException(),
|
"RDE XML schema validation failed: %s\n%s%s\n",
|
||||||
getMarshaller().marshalLenient(element));
|
resource.createVKey(),
|
||||||
|
e.getLinkedException(),
|
||||||
|
getMarshaller().marshalLenient(element));
|
||||||
logger.atSevere().withCause(e).log(error);
|
logger.atSevere().withCause(e).log(error);
|
||||||
}
|
}
|
||||||
return DepositFragment.create(type, xml, error);
|
return DepositFragment.create(type, xml, error);
|
||||||
|
|
|
@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.flogger.FluentLogger;
|
import com.google.common.flogger.FluentLogger;
|
||||||
import google.registry.model.EppResource;
|
import google.registry.model.EppResource;
|
||||||
|
import google.registry.model.adapters.EnumToAttributeAdapter.EppEnum;
|
||||||
import google.registry.model.contact.Contact;
|
import google.registry.model.contact.Contact;
|
||||||
import google.registry.model.contact.ContactPhoneNumber;
|
import google.registry.model.contact.ContactPhoneNumber;
|
||||||
import google.registry.model.contact.PostalInfo;
|
import google.registry.model.contact.PostalInfo;
|
||||||
|
@ -33,7 +34,6 @@ import google.registry.model.domain.GracePeriod;
|
||||||
import google.registry.model.eppcommon.StatusValue;
|
import google.registry.model.eppcommon.StatusValue;
|
||||||
import google.registry.model.registrar.Registrar;
|
import google.registry.model.registrar.Registrar;
|
||||||
import google.registry.model.registrar.RegistrarPoc;
|
import google.registry.model.registrar.RegistrarPoc;
|
||||||
import google.registry.model.translators.EnumToAttributeAdapter.EppEnum;
|
|
||||||
import google.registry.persistence.VKey;
|
import google.registry.persistence.VKey;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
|
@ -21,7 +21,7 @@ import google.registry.testing.FakeClock;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
|
||||||
/** Base class of all unit tests for entities which are persisted to Datastore via Objectify. */
|
/** Base class of all unit tests for entities which are persisted to SQL. */
|
||||||
public abstract class EntityTestCase {
|
public abstract class EntityTestCase {
|
||||||
|
|
||||||
protected enum JpaEntityCoverageCheck {
|
protected enum JpaEntityCoverageCheck {
|
||||||
|
|
|
@ -17,7 +17,6 @@ package google.registry.model;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.googlecode.objectify.annotation.Id;
|
|
||||||
import google.registry.testing.AppEngineExtension;
|
import google.registry.testing.AppEngineExtension;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -34,14 +33,13 @@ public class ModelUtilsTest {
|
||||||
/** Test class for reflection methods. */
|
/** Test class for reflection methods. */
|
||||||
public static class TestClass extends ImmutableObject implements Buildable {
|
public static class TestClass extends ImmutableObject implements Buildable {
|
||||||
|
|
||||||
@Id
|
|
||||||
String id;
|
String id;
|
||||||
|
|
||||||
String a;
|
String a;
|
||||||
|
|
||||||
String b;
|
String b;
|
||||||
|
|
||||||
/** Note that there is no getter for {@link #b}.*/
|
/** Note that there is no getter for {@link #b}. */
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
@ -50,7 +48,7 @@ public class ModelUtilsTest {
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Builder for {@link TestClass}. Note that there is no setter for {@link #a}.*/
|
/** Builder for {@link TestClass}. Note that there is no setter for {@link #a}. */
|
||||||
public static class Builder extends Buildable.Builder<TestClass> {
|
public static class Builder extends Buildable.Builder<TestClass> {
|
||||||
|
|
||||||
protected Builder() {}
|
protected Builder() {}
|
||||||
|
@ -83,10 +81,11 @@ public class ModelUtilsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testGetAllFields() throws Exception {
|
void testGetAllFields() throws Exception {
|
||||||
Map<String, Field> expected = ImmutableMap.of(
|
Map<String, Field> expected =
|
||||||
"id", TestClass.class.getDeclaredField("id"),
|
ImmutableMap.of(
|
||||||
"a", TestClass.class.getDeclaredField("a"),
|
"id", TestClass.class.getDeclaredField("id"),
|
||||||
"b", TestClass.class.getDeclaredField("b"));
|
"a", TestClass.class.getDeclaredField("a"),
|
||||||
|
"b", TestClass.class.getDeclaredField("b"));
|
||||||
// More complicated version of isEqualTo() so that we check for ordering.
|
// More complicated version of isEqualTo() so that we check for ordering.
|
||||||
assertThat(ModelUtils.getAllFields(TestClass.class).entrySet())
|
assertThat(ModelUtils.getAllFields(TestClass.class).entrySet())
|
||||||
.containsExactlyElementsIn(expected.entrySet())
|
.containsExactlyElementsIn(expected.entrySet())
|
||||||
|
@ -127,7 +126,7 @@ public class ModelUtilsTest {
|
||||||
original.id = "foo";
|
original.id = "foo";
|
||||||
TestClass cloned = original.asBuilder().setId("bar").build();
|
TestClass cloned = original.asBuilder().setId("bar").build();
|
||||||
assertThat(cloned.hashCode()).isNotEqualTo(original.hashCode());
|
assertThat(cloned.hashCode()).isNotEqualTo(original.hashCode());
|
||||||
cloned.id = "foo"; // Violates immutability contract.
|
cloned.id = "foo"; // Violates immutability contract.
|
||||||
// The hashCode is now cached and is stale (but that's the expected behavior).
|
// The hashCode is now cached and is stale (but that's the expected behavior).
|
||||||
assertThat(cloned.hashCode()).isNotEqualTo(original.hashCode());
|
assertThat(cloned.hashCode()).isNotEqualTo(original.hashCode());
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package google.registry.model.translators;
|
package google.registry.model.adapters;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
|
@ -888,9 +888,7 @@ public class DomainTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testHistoryIdRestoration() {
|
void testHistoryIdRestoration() {
|
||||||
// Verify that history ids for billing events are restored during load from datastore. History
|
// Verify that history ids for billing events are restored during load.
|
||||||
// ids are not used by business code or persisted in datastore, but only to reconstruct
|
|
||||||
// objectify keys when loading from SQL.
|
|
||||||
DateTime now = fakeClock.nowUtc();
|
DateTime now = fakeClock.nowUtc();
|
||||||
domain =
|
domain =
|
||||||
persistResource(
|
persistResource(
|
||||||
|
|
|
@ -20,15 +20,14 @@ import static google.registry.persistence.transaction.QueryComposer.Comparator;
|
||||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||||
import static org.junit.Assert.assertThrows;
|
import static org.junit.Assert.assertThrows;
|
||||||
|
|
||||||
import com.googlecode.objectify.annotation.Entity;
|
|
||||||
import com.googlecode.objectify.annotation.Id;
|
|
||||||
import com.googlecode.objectify.annotation.Index;
|
|
||||||
import google.registry.model.ImmutableObject;
|
import google.registry.model.ImmutableObject;
|
||||||
import google.registry.testing.AppEngineExtension;
|
import google.registry.persistence.transaction.JpaTestExtensions.JpaUnitTestExtension;
|
||||||
import google.registry.testing.DatabaseHelper;
|
import google.registry.testing.DatabaseHelper;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
import javax.persistence.NoResultException;
|
import javax.persistence.NoResultException;
|
||||||
import javax.persistence.NonUniqueResultException;
|
import javax.persistence.NonUniqueResultException;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
@ -44,13 +43,11 @@ public class QueryComposerTest {
|
||||||
TestEntity charlie = new TestEntity("charlie", 1);
|
TestEntity charlie = new TestEntity("charlie", 1);
|
||||||
|
|
||||||
@RegisterExtension
|
@RegisterExtension
|
||||||
public final AppEngineExtension appEngine =
|
public final JpaUnitTestExtension jpa =
|
||||||
AppEngineExtension.builder()
|
new JpaTestExtensions.Builder()
|
||||||
.withClock(fakeClock)
|
.withClock(fakeClock)
|
||||||
.withCloudSql()
|
.withEntityClass(TestEntity.class)
|
||||||
.withOfyTestEntities(TestEntity.class)
|
.buildUnitTestExtension();
|
||||||
.withJpaUnitTestEntities(TestEntity.class)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
public QueryComposerTest() {}
|
public QueryComposerTest() {}
|
||||||
|
|
||||||
|
@ -319,12 +316,10 @@ public class QueryComposerTest {
|
||||||
.isEmpty();
|
.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@javax.persistence.Entity
|
@Entity
|
||||||
@Entity(name = "QueryComposerTestEntity")
|
|
||||||
private static class TestEntity extends ImmutableObject {
|
private static class TestEntity extends ImmutableObject {
|
||||||
@javax.persistence.Id @Id private String name;
|
@Id private String name;
|
||||||
|
|
||||||
@Index
|
|
||||||
// Renaming this implicitly verifies that property names work for hibernate queries.
|
// Renaming this implicitly verifies that property names work for hibernate queries.
|
||||||
@Column(name = "some_value")
|
@Column(name = "some_value")
|
||||||
private int val;
|
private int val;
|
||||||
|
|
|
@ -1125,7 +1125,7 @@ public final class DatabaseHelper {
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Persists a single Objectify resource, without adjusting foreign resources or keys. */
|
/** Persists a single resource, without adjusting foreign resources or keys. */
|
||||||
public static <R> R persistSimpleResource(final R resource) {
|
public static <R> R persistSimpleResource(final R resource) {
|
||||||
return persistSimpleResources(ImmutableList.of(resource)).get(0);
|
return persistSimpleResources(ImmutableList.of(resource)).get(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ public final class DiffUtils {
|
||||||
&& aValue == null
|
&& aValue == null
|
||||||
&& bValue instanceof Collection
|
&& bValue instanceof Collection
|
||||||
&& ((Collection<?>) bValue).isEmpty()) {
|
&& ((Collection<?>) bValue).isEmpty()) {
|
||||||
// Ignore a mismatch between Objectify's use of null to store empty collections and our
|
// Ignore a mismatch between the use of null to store empty collections and our
|
||||||
// code's builder methods, which yield empty collections for the same fields. This
|
// code's builder methods, which yield empty collections for the same fields. This
|
||||||
// prevents useless lines of the form "[null, []]" from appearing in diffs.
|
// prevents useless lines of the form "[null, []]" from appearing in diffs.
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Add table
Reference in a new issue