mirror of
https://github.com/google/nomulus.git
synced 2025-05-15 08:57:12 +02:00
Run automatic Java 8 conversion over codebase
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=171174380
This commit is contained in:
parent
44df5da771
commit
5edb7935ed
190 changed files with 2312 additions and 3096 deletions
|
@ -116,17 +116,12 @@ public final class EntityClasses {
|
|||
/**
|
||||
* Function that converts an Objectify-registered class to its Datastore kind name.
|
||||
*
|
||||
* <p>Note that this mapping is not one-to-one, since polymorphic subclasses of an entity all
|
||||
* have the same Datastore kind. (In theory, two distinct top-level entities could also map to
|
||||
* the same kind since it's just {@code class.getSimpleName()}, but we test against that.)
|
||||
* <p>Note that this mapping is not one-to-one, since polymorphic subclasses of an entity all have
|
||||
* the same Datastore kind. (In theory, two distinct top-level entities could also map to the same
|
||||
* kind since it's just {@code class.getSimpleName()}, but we test against that.)
|
||||
*/
|
||||
public static final Function<Class<? extends ImmutableObject>, String> CLASS_TO_KIND_FUNCTION =
|
||||
new Function<Class<? extends ImmutableObject>, String>() {
|
||||
@Override
|
||||
public String apply(Class<? extends ImmutableObject> clazz) {
|
||||
return Key.getKind(clazz);
|
||||
}
|
||||
};
|
||||
(Class<? extends ImmutableObject> clazz) -> Key.getKind(clazz);
|
||||
|
||||
private EntityClasses() {}
|
||||
}
|
||||
|
|
|
@ -172,11 +172,7 @@ public final class EppResourceUtils {
|
|||
* Iterables.transform() over a collection of EppResources.
|
||||
*/
|
||||
public static <T extends EppResource> Function<T, T> transformAtTime(final DateTime now) {
|
||||
return new Function<T, T>() {
|
||||
@Override
|
||||
public T apply(T resource) {
|
||||
return cloneProjectedAtTime(resource, now);
|
||||
}};
|
||||
return (T resource) -> cloneProjectedAtTime(resource, now);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
package google.registry.model;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.collect.Iterables.transform;
|
||||
import static com.google.common.collect.Maps.transformValues;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
|
@ -22,7 +24,6 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.Ignore;
|
||||
|
@ -157,30 +158,33 @@ public abstract class ImmutableObject implements Cloneable {
|
|||
}};
|
||||
|
||||
/** Helper function to recursively convert a ImmutableObject to a Map of generic objects. */
|
||||
private static final Function<Object, Object> TO_MAP_HELPER = new Function<Object, Object>() {
|
||||
@Override
|
||||
public Object apply(Object o) {
|
||||
if (o == null) {
|
||||
return null;
|
||||
} else if (o instanceof ImmutableObject) {
|
||||
// LinkedHashMap to preserve field ordering and because ImmutableMap forbids null values.
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
for (Entry<Field, Object> entry : ModelUtils.getFieldValues(o).entrySet()) {
|
||||
result.put(entry.getKey().getName(), apply(entry.getValue()));
|
||||
private static final Function<Object, Object> TO_MAP_HELPER =
|
||||
new Function<Object, Object>() {
|
||||
@Override
|
||||
public Object apply(Object o) {
|
||||
if (o == null) {
|
||||
return null;
|
||||
} else if (o instanceof ImmutableObject) {
|
||||
// LinkedHashMap to preserve field ordering and because ImmutableMap forbids null
|
||||
// values.
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
for (Entry<Field, Object> entry : ModelUtils.getFieldValues(o).entrySet()) {
|
||||
result.put(entry.getKey().getName(), apply(entry.getValue()));
|
||||
}
|
||||
return result;
|
||||
} else if (o instanceof Map) {
|
||||
return Maps.transformValues((Map<?, ?>) o, this);
|
||||
} else if (o instanceof Set) {
|
||||
return ((Set<?>) o).stream().map(this).collect(toImmutableSet());
|
||||
} else if (o instanceof Collection) {
|
||||
return ((Collection<?>) o).stream().map(this).collect(toImmutableList());
|
||||
} else if (o instanceof Number || o instanceof Boolean) {
|
||||
return o;
|
||||
} else {
|
||||
return o.toString();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} else if (o instanceof Map) {
|
||||
return Maps.transformValues((Map<?, ?>) o, this);
|
||||
} else if (o instanceof Set) {
|
||||
return FluentIterable.from((Set<?>) o).transform(this).toSet();
|
||||
} else if (o instanceof Collection) {
|
||||
return FluentIterable.from((Collection<?>) o).transform(this).toList();
|
||||
} else if (o instanceof Number || o instanceof Boolean) {
|
||||
return o;
|
||||
} else {
|
||||
return o.toString();
|
||||
}
|
||||
}};
|
||||
};
|
||||
|
||||
/** Returns a map of all object fields (including sensitive data) that's used to produce diffs. */
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
@ -14,9 +14,10 @@
|
|||
|
||||
package google.registry.model;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
|
||||
import com.google.common.base.Functions;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.Streams;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
@ -29,14 +30,6 @@ import javax.annotation.Nullable;
|
|||
* list is passed as {@code null}, it'll be substituted with empty list. Lists are not mutable.
|
||||
*/
|
||||
public final class JsonMapBuilder {
|
||||
|
||||
private static final Function<Jsonifiable, Map<String, Object>> TO_JSON_OBJECT =
|
||||
new Function<Jsonifiable, Map<String, Object>>() {
|
||||
@Override
|
||||
public Map<String, Object> apply(Jsonifiable input) {
|
||||
return input.toJsonMap();
|
||||
}};
|
||||
|
||||
private final Map<String, Object> map = new LinkedHashMap<>();
|
||||
|
||||
public JsonMapBuilder put(String name, @Nullable Boolean value) {
|
||||
|
@ -70,15 +63,21 @@ public final class JsonMapBuilder {
|
|||
}
|
||||
|
||||
public <T> JsonMapBuilder putListOfStrings(String name, @Nullable Iterable<T> value) {
|
||||
map.put(name, value == null ? Collections.EMPTY_LIST
|
||||
: FluentIterable.from(value).transform(Functions.toStringFunction()).toList());
|
||||
map.put(
|
||||
name,
|
||||
value == null
|
||||
? Collections.EMPTY_LIST
|
||||
: Streams.stream(value).map(Functions.toStringFunction()).collect(toImmutableList()));
|
||||
return this;
|
||||
}
|
||||
|
||||
public JsonMapBuilder putListOfJsonObjects(
|
||||
String name, @Nullable Iterable<? extends Jsonifiable> value) {
|
||||
map.put(name, value == null ? Collections.EMPTY_LIST
|
||||
: FluentIterable.from(value).transform(TO_JSON_OBJECT).toList());
|
||||
map.put(
|
||||
name,
|
||||
value == null
|
||||
? Collections.EMPTY_LIST
|
||||
: Streams.stream(value).map(Jsonifiable::toJsonMap).collect(toImmutableList()));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ package google.registry.model;
|
|||
import static com.google.common.base.Predicates.instanceOf;
|
||||
import static com.google.common.base.Predicates.isNull;
|
||||
import static com.google.common.base.Predicates.or;
|
||||
import static com.google.common.collect.Iterables.all;
|
||||
import static com.google.common.collect.Lists.newArrayList;
|
||||
import static com.google.common.collect.Maps.transformValues;
|
||||
import static com.google.common.collect.Sets.newLinkedHashSet;
|
||||
|
@ -34,6 +33,7 @@ import com.google.common.collect.ImmutableMap;
|
|||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.Id;
|
||||
import com.googlecode.objectify.annotation.Ignore;
|
||||
|
@ -95,25 +95,21 @@ public class ModelUtils {
|
|||
body = FluentIterable.from(clazz.getEnumConstants());
|
||||
} else {
|
||||
stringBuilder.append("class ");
|
||||
body = FluentIterable.from(getAllFields(clazz).values())
|
||||
.filter(new Predicate<Field>() {
|
||||
@Override
|
||||
public boolean apply(Field field) {
|
||||
return !field.isAnnotationPresent(Ignore.class);
|
||||
}})
|
||||
.transform(new Function<Field, Object>() {
|
||||
@Override
|
||||
public Object apply(Field 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());
|
||||
}});
|
||||
body =
|
||||
FluentIterable.from(getAllFields(clazz).values())
|
||||
.filter((Field field) -> !field.isAnnotationPresent(Ignore.class))
|
||||
.transform(
|
||||
(Field 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 ")
|
||||
|
@ -212,45 +208,48 @@ public class ModelUtils {
|
|||
}
|
||||
|
||||
/** Functional helper for {@link #cloneEmptyToNull}. */
|
||||
private static final Function<Object, ?> CLONE_EMPTY_TO_NULL = new Function<Object, Object>() {
|
||||
@Override
|
||||
public Object apply(Object obj) {
|
||||
if (obj instanceof ImmutableSortedMap) {
|
||||
// ImmutableSortedMapTranslatorFactory handles empty for us. If the object is null, then
|
||||
// its on-save hook can't run.
|
||||
private static final Function<Object, ?> CLONE_EMPTY_TO_NULL =
|
||||
new Function<Object, Object>() {
|
||||
@Override
|
||||
public Object apply(Object obj) {
|
||||
if (obj instanceof ImmutableSortedMap) {
|
||||
// ImmutableSortedMapTranslatorFactory handles empty for us. If the object is null, then
|
||||
// its on-save hook can't run.
|
||||
return obj;
|
||||
}
|
||||
if ("".equals(obj)
|
||||
|| (obj instanceof Collection && ((Collection<?>) obj).isEmpty())
|
||||
|| (obj instanceof Map && ((Map<?, ?>) obj).isEmpty())
|
||||
|| (obj != null && obj.getClass().isArray() && Array.getLength(obj) == 0)) {
|
||||
return null;
|
||||
}
|
||||
Predicate<Object> immutableObjectOrNull = or(isNull(), instanceOf(ImmutableObject.class));
|
||||
if ((obj instanceof Set || obj instanceof List)
|
||||
&& Streams.stream((Iterable<?>) obj).allMatch(immutableObjectOrNull)) {
|
||||
// Recurse into sets and lists, but only if they contain ImmutableObjects.
|
||||
FluentIterable<?> fluent = FluentIterable.from((Iterable<?>) obj).transform(this);
|
||||
return (obj instanceof List) ? newArrayList(fluent) : newLinkedHashSet(fluent);
|
||||
}
|
||||
if (obj instanceof Map
|
||||
&& ((Map<?, ?>) obj).values().stream().allMatch(immutableObjectOrNull)) {
|
||||
// Recurse into maps with ImmutableObject values.
|
||||
return transformValues((Map<?, ?>) obj, this);
|
||||
}
|
||||
if (obj instanceof ImmutableObject) {
|
||||
// Recurse on the fields of an ImmutableObject.
|
||||
ImmutableObject copy = ImmutableObject.clone((ImmutableObject) obj);
|
||||
for (Field field : getAllFields(obj.getClass()).values()) {
|
||||
Object oldValue = getFieldValue(obj, field);
|
||||
Object newValue = apply(oldValue);
|
||||
if (!Objects.equals(oldValue, newValue)) {
|
||||
setFieldValue(copy, field, newValue);
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
if ("".equals(obj)
|
||||
|| (obj instanceof Collection && ((Collection<?>) obj).isEmpty())
|
||||
|| (obj instanceof Map && ((Map<?, ?>) obj).isEmpty())
|
||||
|| (obj != null && obj.getClass().isArray() && Array.getLength(obj) == 0)) {
|
||||
return null;
|
||||
}
|
||||
Predicate<Object> immutableObjectOrNull = or(isNull(), instanceOf(ImmutableObject.class));
|
||||
if ((obj instanceof Set || obj instanceof List)
|
||||
&& all((Iterable<?>) obj, immutableObjectOrNull)) {
|
||||
// Recurse into sets and lists, but only if they contain ImmutableObjects.
|
||||
FluentIterable<?> fluent = FluentIterable.from((Iterable<?>) obj).transform(this);
|
||||
return (obj instanceof List) ? newArrayList(fluent) : newLinkedHashSet(fluent);
|
||||
}
|
||||
if (obj instanceof Map && all(((Map<?, ?>) obj).values(), immutableObjectOrNull)) {
|
||||
// Recurse into maps with ImmutableObject values.
|
||||
return transformValues((Map<?, ?>) obj, this);
|
||||
}
|
||||
if (obj instanceof ImmutableObject) {
|
||||
// Recurse on the fields of an ImmutableObject.
|
||||
ImmutableObject copy = ImmutableObject.clone((ImmutableObject) obj);
|
||||
for (Field field : getAllFields(obj.getClass()).values()) {
|
||||
Object oldValue = getFieldValue(obj, field);
|
||||
Object newValue = apply(oldValue);
|
||||
if (!Objects.equals(oldValue, newValue)) {
|
||||
setFieldValue(copy, field, newValue);
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
return obj;
|
||||
}};
|
||||
};
|
||||
|
||||
/** Returns a clone of the object and sets empty collections, arrays, maps and strings to null. */
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
@ -16,10 +16,8 @@ package google.registry.model;
|
|||
|
||||
import static com.google.common.base.Predicates.or;
|
||||
import static com.google.common.base.Predicates.subtypeOf;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.Ordering;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Queue;
|
||||
|
@ -60,14 +58,11 @@ public final class SchemaVersion {
|
|||
* types (for classes), or else a list of all possible values (for enums).
|
||||
*/
|
||||
public static String getSchema() {
|
||||
return FluentIterable.from(getAllPersistedTypes())
|
||||
return getAllPersistedTypes()
|
||||
.stream()
|
||||
.filter(or(subtypeOf(Enum.class), subtypeOf(ImmutableObject.class)))
|
||||
.transform(new Function<Class<?>, String>() {
|
||||
@Override
|
||||
public String apply(Class<?> clazz) {
|
||||
return ModelUtils.getSchema(clazz);
|
||||
}})
|
||||
.join(Joiner.on('\n'));
|
||||
.map(ModelUtils::getSchema)
|
||||
.collect(joining("\n"));
|
||||
}
|
||||
|
||||
private SchemaVersion() {}
|
||||
|
|
|
@ -14,15 +14,13 @@
|
|||
|
||||
package google.registry.model.billing;
|
||||
|
||||
import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Maps.EntryTransformer;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.googlecode.objectify.cmd.Query;
|
||||
import google.registry.model.CacheUtils;
|
||||
|
@ -38,19 +36,11 @@ public final class RegistrarBillingUtils {
|
|||
|
||||
private static final Supplier<ImmutableSortedSet<CurrencyUnit>> CURRENCIES_CACHE =
|
||||
CacheUtils.memoizeWithShortExpiration(
|
||||
new Supplier<ImmutableSortedSet<CurrencyUnit>>() {
|
||||
@Override
|
||||
public ImmutableSortedSet<CurrencyUnit> get() {
|
||||
return FluentIterable
|
||||
.from(Registries.getTlds())
|
||||
.transform(new Function<String, CurrencyUnit>() {
|
||||
@Override
|
||||
public CurrencyUnit apply(String tld) {
|
||||
return Registry.get(tld).getCurrency();
|
||||
}})
|
||||
.toSortedSet(Ordering.natural());
|
||||
}
|
||||
});
|
||||
() ->
|
||||
Registries.getTlds()
|
||||
.stream()
|
||||
.map((String tld) -> Registry.get(tld).getCurrency())
|
||||
.collect(toImmutableSortedSet(Ordering.natural())));
|
||||
|
||||
/**
|
||||
* Returns set of currencies in which registrars may be billed.
|
||||
|
@ -69,28 +59,25 @@ public final class RegistrarBillingUtils {
|
|||
*/
|
||||
public static ImmutableMap<CurrencyUnit, Query<RegistrarBillingEntry>> getBillingEntryQueries(
|
||||
final Registrar registrar) {
|
||||
return Maps.toMap(getCurrencies(),
|
||||
new Function<CurrencyUnit, Query<RegistrarBillingEntry>>() {
|
||||
@Override
|
||||
public Query<RegistrarBillingEntry> apply(CurrencyUnit currency) {
|
||||
return ofy().load()
|
||||
return Maps.toMap(
|
||||
getCurrencies(),
|
||||
(CurrencyUnit currency) ->
|
||||
ofy()
|
||||
.load()
|
||||
.type(RegistrarBillingEntry.class)
|
||||
.ancestor(registrar)
|
||||
.filter("currency", currency)
|
||||
.order("-created");
|
||||
}});
|
||||
.order("-created"));
|
||||
}
|
||||
|
||||
/** Returns amount of money registrar currently owes registry in each currency. */
|
||||
public static Map<CurrencyUnit, Money> loadBalance(Registrar registrar) {
|
||||
return Maps.transformEntries(getBillingEntryQueries(registrar),
|
||||
new EntryTransformer<CurrencyUnit, Query<RegistrarBillingEntry>, Money>() {
|
||||
@Override
|
||||
public Money transformEntry(
|
||||
CurrencyUnit currency, Query<RegistrarBillingEntry> query) {
|
||||
RegistrarBillingEntry entry = query.first().now();
|
||||
return entry != null ? entry.getBalance() : Money.zero(currency);
|
||||
}});
|
||||
return Maps.transformEntries(
|
||||
getBillingEntryQueries(registrar),
|
||||
(CurrencyUnit currency, Query<RegistrarBillingEntry> query) -> {
|
||||
RegistrarBillingEntry entry = query.first().now();
|
||||
return entry != null ? entry.getBalance() : Money.zero(currency);
|
||||
});
|
||||
}
|
||||
|
||||
private RegistrarBillingUtils() {}
|
||||
|
|
|
@ -16,15 +16,16 @@ package google.registry.model.billing;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.model.registry.Registries.assertTldExists;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ComparisonChain;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
import com.googlecode.objectify.annotation.Id;
|
||||
|
@ -216,7 +217,8 @@ public final class RegistrarCredit extends ImmutableObject implements Buildable
|
|||
* <p>The resulting list sorts the credits first by type and then by creation time.
|
||||
*/
|
||||
public static ImmutableList<RegistrarCredit> loadAllForRegistrar(Registrar registrar) {
|
||||
return FluentIterable.from(ofy().load().type(RegistrarCredit.class).ancestor(registrar))
|
||||
.toSortedList(CREDIT_PRIORITY_ORDERING);
|
||||
return Streams.stream(ofy().load().type(RegistrarCredit.class).ancestor(registrar))
|
||||
.sorted(CREDIT_PRIORITY_ORDERING)
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ import static com.google.common.base.Preconditions.checkState;
|
|||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ForwardingNavigableMap;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
|
@ -193,16 +192,12 @@ public final class RegistrarCreditBalance extends ImmutableObject implements Bui
|
|||
*/
|
||||
@VisibleForTesting
|
||||
BalanceMap(Map<DateTime, ? extends Map<DateTime, Money>> data) {
|
||||
delegate = ImmutableSortedMap.copyOf(
|
||||
Maps.transformValues(
|
||||
data,
|
||||
new Function<Map<DateTime, Money>, ImmutableSortedMap<DateTime, Money>>() {
|
||||
@Override
|
||||
public ImmutableSortedMap<DateTime, Money> apply(Map<DateTime, Money> map) {
|
||||
return ImmutableSortedMap.copyOf(map, Ordering.natural());
|
||||
}
|
||||
}),
|
||||
Ordering.natural());
|
||||
delegate =
|
||||
ImmutableSortedMap.copyOf(
|
||||
Maps.transformValues(
|
||||
data,
|
||||
(Map<DateTime, Money> map) -> ImmutableSortedMap.copyOf(map, Ordering.natural())),
|
||||
Ordering.natural());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -21,7 +21,6 @@ import static google.registry.util.DateTimeUtils.isAtOrAfter;
|
|||
import static google.registry.util.DateTimeUtils.isBeforeOrAt;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ContiguousSet;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
|
@ -85,11 +84,7 @@ public class TimeOfYear extends ImmutableObject {
|
|||
normalizedRange.lowerEndpoint().getYear(),
|
||||
normalizedRange.upperEndpoint().getYear());
|
||||
return FluentIterable.from(ContiguousSet.create(yearRange, integers()))
|
||||
.transform(new Function<Integer, DateTime>() {
|
||||
@Override
|
||||
public DateTime apply(Integer year) {
|
||||
return getDateTimeWithYear(year);
|
||||
}})
|
||||
.transform(this::getDateTimeWithYear)
|
||||
.filter(normalizedRange);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ import static google.registry.util.CollectionUtils.nullToEmpty;
|
|||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.latestOf;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ForwardingMap;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
|
@ -103,18 +102,17 @@ public class TimedTransitionProperty<V, T extends TimedTransitionProperty.TimedT
|
|||
checkArgument(
|
||||
Ordering.natural().equals(valueMap.comparator()),
|
||||
"Timed transition value map must have transition time keys in chronological order");
|
||||
return Maps.transformEntries(valueMap, new Maps.EntryTransformer<DateTime, V, T>() {
|
||||
// For each entry in the input value map, make the output map have an entry at the
|
||||
// corresponding time that points to a transition containing that time and that value.
|
||||
@Override
|
||||
public T transformEntry(DateTime transitionTime, V value) {
|
||||
checkArgument(!transitionTime.isBefore(START_OF_TIME),
|
||||
return Maps.transformEntries(
|
||||
valueMap,
|
||||
(DateTime transitionTime, V value) -> {
|
||||
checkArgument(
|
||||
!transitionTime.isBefore(START_OF_TIME),
|
||||
"Timed transition times cannot be earlier than START_OF_TIME / Unix Epoch");
|
||||
T subclass = TypeUtils.instantiate(timedTransitionSubclass);
|
||||
((TimedTransition<V>) subclass).transitionTime = transitionTime;
|
||||
subclass.setValue(value);
|
||||
return subclass;
|
||||
}});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -288,13 +286,7 @@ public class TimedTransitionProperty<V, T extends TimedTransitionProperty.TimedT
|
|||
|
||||
/** Returns the map of DateTime to value that is the "natural" representation of this property. */
|
||||
public ImmutableSortedMap<DateTime, V> toValueMap() {
|
||||
return ImmutableSortedMap.copyOfSorted(Maps.transformValues(
|
||||
backingMap,
|
||||
new Function<T, V>() {
|
||||
@Override
|
||||
public V apply(T timedTransition) {
|
||||
return timedTransition.getValue();
|
||||
}}));
|
||||
return ImmutableSortedMap.copyOfSorted(Maps.transformValues(backingMap, T::getValue));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,7 +17,6 @@ package google.registry.model.contact;
|
|||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static google.registry.util.CollectionUtils.nullToEmpty;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Maps;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.contact.PostalInfo.Type;
|
||||
|
@ -67,11 +66,7 @@ public class ContactCommand {
|
|||
// There can be no more than 2 postalInfos (enforced by the schema), and if there are 2 they
|
||||
// must be of different types (not enforced). If the type is repeated, uniqueIndex will throw.
|
||||
checkState(nullToEmpty(postalInfo).size() <= 2);
|
||||
return Maps.uniqueIndex(nullToEmpty(postalInfo), new Function<PostalInfo, Type>() {
|
||||
@Override
|
||||
public Type apply(PostalInfo info) {
|
||||
return info.getType();
|
||||
}});
|
||||
return Maps.uniqueIndex(nullToEmpty(postalInfo), PostalInfo::getType);
|
||||
}
|
||||
|
||||
public ContactPhoneNumber getVoice() {
|
||||
|
|
|
@ -15,13 +15,12 @@
|
|||
package google.registry.model.contact;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static google.registry.model.EppResourceUtils.projectResourceOntoBuilderAtTime;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
import com.googlecode.objectify.annotation.IgnoreSave;
|
||||
import com.googlecode.objectify.annotation.Index;
|
||||
|
@ -33,6 +32,7 @@ import google.registry.model.annotations.ExternalMessagingName;
|
|||
import google.registry.model.annotations.ReportedOn;
|
||||
import google.registry.model.contact.PostalInfo.Type;
|
||||
import google.registry.model.transfer.TransferData;
|
||||
import java.util.stream.Stream;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
|
@ -170,10 +170,9 @@ public class ContactResource extends EppResource implements
|
|||
*/
|
||||
@XmlElement(name = "postalInfo")
|
||||
public ImmutableList<PostalInfo> getPostalInfosAsList() {
|
||||
return FluentIterable
|
||||
.from(Lists.newArrayList(localizedPostalInfo, internationalizedPostalInfo))
|
||||
return Stream.of(localizedPostalInfo, internationalizedPostalInfo)
|
||||
.filter(Predicates.notNull())
|
||||
.toList();
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,8 +17,8 @@ package google.registry.model.domain;
|
|||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Predicates.not;
|
||||
import static com.google.common.base.Strings.emptyToNull;
|
||||
import static com.google.common.collect.Iterables.all;
|
||||
import static com.google.common.collect.Iterables.any;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;
|
||||
import static com.google.common.collect.Sets.difference;
|
||||
import static com.google.common.collect.Sets.union;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
|
@ -30,9 +30,7 @@ import static google.registry.util.DomainNameUtils.canonicalizeDomainName;
|
|||
import static google.registry.util.DomainNameUtils.getTldFromDomainName;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.common.collect.Ordering;
|
||||
|
@ -49,6 +47,7 @@ import google.registry.model.domain.launch.LaunchNotice;
|
|||
import google.registry.model.domain.secdns.DelegationSignerData;
|
||||
import google.registry.model.host.HostResource;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/** Shared base class for {@link DomainResource} and {@link DomainApplication}. */
|
||||
@ReportedOn
|
||||
|
@ -134,33 +133,28 @@ public abstract class DomainBase extends EppResource {
|
|||
|
||||
/** Loads and returns the fully qualified host names of all linked nameservers. */
|
||||
public ImmutableSortedSet<String> loadNameserverFullyQualifiedHostNames() {
|
||||
return FluentIterable.from(ofy().load().keys(getNameservers()).values())
|
||||
.transform(
|
||||
new Function<HostResource, String>() {
|
||||
@Override
|
||||
public String apply(HostResource host) {
|
||||
return host.getFullyQualifiedHostName();
|
||||
}
|
||||
})
|
||||
.toSortedSet(Ordering.natural());
|
||||
return ofy()
|
||||
.load()
|
||||
.keys(getNameservers())
|
||||
.values()
|
||||
.stream()
|
||||
.map(HostResource::getFullyQualifiedHostName)
|
||||
.collect(toImmutableSortedSet(Ordering.natural()));
|
||||
}
|
||||
|
||||
/** A key to the registrant who registered this domain. */
|
||||
public Key<ContactResource> getRegistrant() {
|
||||
return FluentIterable
|
||||
.from(nullToEmpty(allContacts))
|
||||
return nullToEmpty(allContacts)
|
||||
.stream()
|
||||
.filter(IS_REGISTRANT)
|
||||
.first()
|
||||
.findFirst()
|
||||
.get()
|
||||
.getContactKey();
|
||||
}
|
||||
|
||||
/** Associated contacts for the domain (other than registrant). */
|
||||
public ImmutableSet<DesignatedContact> getContacts() {
|
||||
return FluentIterable
|
||||
.from(nullToEmpty(allContacts))
|
||||
.filter(not(IS_REGISTRANT))
|
||||
.toSet();
|
||||
return nullToEmpty(allContacts).stream().filter(not(IS_REGISTRANT)).collect(toImmutableSet());
|
||||
}
|
||||
|
||||
public DomainAuthInfo getAuthInfo() {
|
||||
|
@ -183,11 +177,7 @@ public abstract class DomainBase extends EppResource {
|
|||
|
||||
/** Predicate to determine if a given {@link DesignatedContact} is the registrant. */
|
||||
private static final Predicate<DesignatedContact> IS_REGISTRANT =
|
||||
new Predicate<DesignatedContact>() {
|
||||
@Override
|
||||
public boolean apply(DesignatedContact contact) {
|
||||
return DesignatedContact.Type.REGISTRANT.equals(contact.type);
|
||||
}};
|
||||
(DesignatedContact contact) -> DesignatedContact.Type.REGISTRANT.equals(contact.type);
|
||||
|
||||
/** An override of {@link EppResource#asBuilder} with tighter typing. */
|
||||
@Override
|
||||
|
@ -208,7 +198,7 @@ public abstract class DomainBase extends EppResource {
|
|||
T instance = getInstance();
|
||||
checkArgumentNotNull(
|
||||
emptyToNull(instance.fullyQualifiedDomainName), "Missing fullyQualifiedDomainName");
|
||||
checkArgument(any(instance.allContacts, IS_REGISTRANT), "Missing registrant");
|
||||
checkArgument(instance.allContacts.stream().anyMatch(IS_REGISTRANT), "Missing registrant");
|
||||
instance.tld = getTldFromDomainName(instance.fullyQualifiedDomainName);
|
||||
return super.build();
|
||||
}
|
||||
|
@ -255,13 +245,13 @@ public abstract class DomainBase extends EppResource {
|
|||
}
|
||||
|
||||
public B setContacts(ImmutableSet<DesignatedContact> contacts) {
|
||||
checkArgument(all(contacts, not(IS_REGISTRANT)), "Registrant cannot be a contact");
|
||||
checkArgument(contacts.stream().noneMatch(IS_REGISTRANT), "Registrant cannot be a contact");
|
||||
// Replace the non-registrant contacts inside allContacts.
|
||||
getInstance().allContacts = FluentIterable
|
||||
.from(nullToEmpty(getInstance().allContacts))
|
||||
.filter(IS_REGISTRANT)
|
||||
.append(contacts)
|
||||
.toSet();
|
||||
getInstance().allContacts =
|
||||
Stream.concat(
|
||||
nullToEmpty(getInstance().allContacts).stream().filter(IS_REGISTRANT),
|
||||
contacts.stream())
|
||||
.collect(toImmutableSet());
|
||||
return thisCastToDerived();
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@ import static google.registry.util.CollectionUtils.nullToEmpty;
|
|||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
import static google.registry.util.CollectionUtils.union;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
@ -458,13 +457,7 @@ public class DomainCommand {
|
|||
throw new InvalidReferencesException(
|
||||
clazz, ImmutableSet.copyOf(difference(foreignKeys, fkis.keySet())));
|
||||
}
|
||||
return ImmutableMap.copyOf(transformValues(
|
||||
fkis,
|
||||
new Function<ForeignKeyIndex<T>, Key<T>>() {
|
||||
@Override
|
||||
public Key<T> apply(ForeignKeyIndex<T> fki) {
|
||||
return fki.getResourceKey();
|
||||
}}));
|
||||
return ImmutableMap.copyOf(transformValues(fkis, ForeignKeyIndex::getResourceKey));
|
||||
}
|
||||
|
||||
/** Exception to throw when referenced objects don't exist. */
|
||||
|
|
|
@ -16,14 +16,12 @@ package google.registry.model.domain.rgp;
|
|||
|
||||
import static com.google.common.base.Predicates.equalTo;
|
||||
import static com.google.common.base.Predicates.not;
|
||||
import static java.util.Arrays.asList;
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Maps;
|
||||
import google.registry.model.translators.EnumToAttributeAdapter;
|
||||
import google.registry.model.translators.EnumToAttributeAdapter.EppEnum;
|
||||
import java.util.stream.Stream;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
@ -101,15 +99,12 @@ public enum GracePeriodStatus implements EppEnum {
|
|||
|
||||
/** Provide a quick lookup of GracePeriodStatus from XML name. */
|
||||
private static final ImmutableMap<String, GracePeriodStatus> XML_NAME_TO_GRACE_PERIOD_STATUS =
|
||||
Maps.uniqueIndex(
|
||||
// SUNRUSH_ADD isn't a real grace period type visible in EPP XML, so exclude it.
|
||||
Iterables.filter(asList(GracePeriodStatus.values()), not(equalTo(SUNRUSH_ADD))),
|
||||
new Function<GracePeriodStatus, String>() {
|
||||
@Override
|
||||
public String apply(GracePeriodStatus gracePeriodStatus) {
|
||||
return gracePeriodStatus.xmlName;
|
||||
}
|
||||
});
|
||||
Stream.of(GracePeriodStatus.values())
|
||||
.filter(not(equalTo(SUNRUSH_ADD)))
|
||||
.collect(
|
||||
toImmutableMap(
|
||||
(GracePeriodStatus gracePeriodStatus) -> gracePeriodStatus.xmlName,
|
||||
value -> value));
|
||||
|
||||
@XmlAttribute(name = "s")
|
||||
private final String xmlName;
|
||||
|
|
|
@ -14,11 +14,9 @@
|
|||
|
||||
package google.registry.model.eppcommon;
|
||||
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.collect.Maps.uniqueIndex;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.domain.allocate.AllocateCreateExtension;
|
||||
|
@ -98,16 +96,9 @@ public class ProtocolDefinition {
|
|||
}
|
||||
|
||||
/** Converts a service extension enum to its URI. */
|
||||
private static final Function<ServiceExtension, String> TO_URI_FUNCTION =
|
||||
new Function<ServiceExtension, String>() {
|
||||
@Override
|
||||
public String apply(ServiceExtension serviceExtension) {
|
||||
return serviceExtension.getUri();
|
||||
}};
|
||||
|
||||
/** This stores a map from URI back to the service extension enum. */
|
||||
private static final ImmutableMap<String, ServiceExtension> serviceExtensionByUri =
|
||||
uniqueIndex(EnumSet.allOf(ServiceExtension.class), TO_URI_FUNCTION);
|
||||
uniqueIndex(EnumSet.allOf(ServiceExtension.class), ServiceExtension::getUri);
|
||||
|
||||
/** Returns the service extension enum associated with a URI, or null if none are associated. */
|
||||
public static ServiceExtension getServiceExtensionFromUri(String uri) {
|
||||
|
@ -116,16 +107,11 @@ public class ProtocolDefinition {
|
|||
|
||||
/** A set of all the visible extension URIs. */
|
||||
private static final ImmutableSet<String> visibleServiceExtensionUris =
|
||||
FluentIterable.from(EnumSet.allOf(ServiceExtension.class))
|
||||
.filter(
|
||||
new Predicate<ServiceExtension>() {
|
||||
@Override
|
||||
public boolean apply(ServiceExtension serviceExtension) {
|
||||
return serviceExtension.getVisible();
|
||||
}
|
||||
})
|
||||
.transform(TO_URI_FUNCTION)
|
||||
.toSet();
|
||||
EnumSet.allOf(ServiceExtension.class)
|
||||
.stream()
|
||||
.filter(ServiceExtension::getVisible)
|
||||
.map(ServiceExtension::getUri)
|
||||
.collect(toImmutableSet());
|
||||
|
||||
/** Return the set of all visible service extension URIs. */
|
||||
public static ImmutableSet<String> getVisibleServiceExtensionUris() {
|
||||
|
|
|
@ -19,7 +19,6 @@ import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
|||
|
||||
import com.google.common.base.Ascii;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.ImmutableObject;
|
||||
|
@ -153,7 +152,13 @@ public class EppInput extends ImmutableObject {
|
|||
/** Get the extension based on type, or null. If there are multiple, it chooses the first. */
|
||||
@Nullable
|
||||
public <E extends CommandExtension> E getSingleExtension(Class<E> clazz) {
|
||||
return FluentIterable.from(getCommandWrapper().getExtensions()).filter(clazz).first().orNull();
|
||||
return getCommandWrapper()
|
||||
.getExtensions()
|
||||
.stream()
|
||||
.filter(clazz::isInstance)
|
||||
.map(clazz::cast)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/** A tag that goes inside of an EPP {@literal <command>}. */
|
||||
|
|
|
@ -17,7 +17,7 @@ package google.registry.model.eppoutput;
|
|||
import static google.registry.util.CollectionUtils.forceEmptyToNull;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.ImmutableObject;
|
||||
|
@ -157,7 +157,9 @@ public class EppResponse extends ImmutableObject implements ResponseOrGreeting {
|
|||
|
||||
@Nullable
|
||||
public ResponseExtension getFirstExtensionOfType(Class<? extends ResponseExtension> clazz) {
|
||||
return FluentIterable.from(extensions).filter(clazz).first().orNull();
|
||||
return Optional.fromJavaUtil(
|
||||
extensions.stream().filter(clazz::isInstance).map(clazz::cast).findFirst())
|
||||
.orNull();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
|
|
@ -18,7 +18,6 @@ import static com.google.common.collect.Maps.filterValues;
|
|||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.util.TypeUtils.instantiate;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.googlecode.objectify.Key;
|
||||
|
@ -166,10 +165,6 @@ public abstract class ForeignKeyIndex<E extends EppResource> extends BackupGroup
|
|||
Class<E> clazz, Iterable<String> foreignKeys, final DateTime now) {
|
||||
return filterValues(
|
||||
ofy().load().type(mapToFkiClass(clazz)).ids(foreignKeys),
|
||||
new Predicate<ForeignKeyIndex<?>>() {
|
||||
@Override
|
||||
public boolean apply(ForeignKeyIndex<?> fki) {
|
||||
return now.isBefore(fki.deletionTime);
|
||||
}});
|
||||
(ForeignKeyIndex<?> fki) -> now.isBefore(fki.deletionTime));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,14 +16,13 @@ package google.registry.model.ofy;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.DiscreteDomain.integers;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static google.registry.config.RegistryConfig.getCommitLogBucketCount;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ContiguousSet;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.common.collect.Range;
|
||||
|
@ -137,13 +136,10 @@ public class CommitLogBucket extends ImmutableObject implements Buildable {
|
|||
|
||||
/** Returns all commit log bucket keys, in ascending order by bucket ID. */
|
||||
public static ImmutableSet<Key<CommitLogBucket>> getAllBucketKeys() {
|
||||
return FluentIterable.from(getBucketIds())
|
||||
.transform(new Function<Integer, Key<CommitLogBucket>>() {
|
||||
@Override
|
||||
public Key<CommitLogBucket> apply(Integer bucketId) {
|
||||
return getBucketKeyUnsafe(bucketId);
|
||||
}})
|
||||
.toSet();
|
||||
return getBucketIds()
|
||||
.stream()
|
||||
.map(CommitLogBucket::getBucketKeyUnsafe)
|
||||
.collect(toImmutableSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,6 +17,7 @@ package google.registry.model.ofy;
|
|||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.base.Predicates.in;
|
||||
import static com.google.common.base.Predicates.not;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.collect.Maps.filterKeys;
|
||||
import static com.google.common.collect.Sets.difference;
|
||||
import static com.google.common.collect.Sets.union;
|
||||
|
@ -25,7 +26,6 @@ import static google.registry.model.ofy.ObjectifyService.ofy;
|
|||
import static google.registry.util.DateTimeUtils.isBeforeOrAt;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.googlecode.objectify.Key;
|
||||
|
@ -150,14 +150,13 @@ class CommitLoggedWork<R> extends VoidWork {
|
|||
ImmutableSet.copyOf(filterKeys(rootsForTouchedKeys, not(in(touchedKeys))).values());
|
||||
manifest = CommitLogManifest.create(info.bucketKey, info.transactionTime, info.getDeletes());
|
||||
final Key<CommitLogManifest> manifestKey = Key.create(manifest);
|
||||
mutations = FluentIterable
|
||||
.from(union(info.getSaves(), untouchedRootsWithTouchedChildren))
|
||||
.transform(new Function<Object, ImmutableObject>() {
|
||||
@Override
|
||||
public CommitLogMutation apply(Object saveEntity) {
|
||||
return CommitLogMutation.create(manifestKey, saveEntity);
|
||||
}})
|
||||
.toSet();
|
||||
mutations =
|
||||
union(info.getSaves(), untouchedRootsWithTouchedChildren)
|
||||
.stream()
|
||||
.map(
|
||||
(Function<Object, ImmutableObject>)
|
||||
(Object saveEntity) -> CommitLogMutation.create(manifestKey, saveEntity))
|
||||
.collect(toImmutableSet());
|
||||
ofy().saveWithoutBackup()
|
||||
.entities(new ImmutableSet.Builder<>()
|
||||
.add(manifest)
|
||||
|
|
|
@ -29,7 +29,7 @@ import com.google.appengine.api.taskqueue.TransientFailureException;
|
|||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.Objectify;
|
||||
import com.googlecode.objectify.ObjectifyFactory;
|
||||
|
@ -136,7 +136,7 @@ public class Ofy {
|
|||
@Override
|
||||
protected void handleDeletion(Iterable<Key<?>> keys) {
|
||||
assertInTransaction();
|
||||
checkState(Iterables.all(keys, notNull()), "Can't delete a null key.");
|
||||
checkState(Streams.stream(keys).allMatch(notNull()), "Can't delete a null key.");
|
||||
checkProhibitedAnnotations(keys, NotBackedUp.class, VirtualEntity.class);
|
||||
TRANSACTION_INFO.get().putDeletes(keys);
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ public class Ofy {
|
|||
@Override
|
||||
protected void handleSave(Iterable<?> entities) {
|
||||
assertInTransaction();
|
||||
checkState(Iterables.all(entities, notNull()), "Can't save a null entity.");
|
||||
checkState(Streams.stream(entities).allMatch(notNull()), "Can't save a null entity.");
|
||||
checkProhibitedAnnotations(entities, NotBackedUp.class, VirtualEntity.class);
|
||||
ImmutableMap<Key<?>, ?> keysToEntities = uniqueIndex(entities, OBJECTS_TO_KEYS);
|
||||
TRANSACTION_INFO.get().putSaves(keysToEntities);
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
package google.registry.model.ofy;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.Objectify;
|
||||
|
@ -43,17 +42,20 @@ class TimestampInversionException extends RuntimeException {
|
|||
}
|
||||
|
||||
private TimestampInversionException(DateTime transactionTime, String problem) {
|
||||
super(Joiner.on('\n').join(
|
||||
String.format(
|
||||
"Timestamp inversion between transaction time (%s) and %s",
|
||||
transactionTime,
|
||||
problem),
|
||||
getFileAndLine(FluentIterable.from(new Exception().getStackTrace())
|
||||
.firstMatch(new Predicate<StackTraceElement>() {
|
||||
@Override
|
||||
public boolean apply(StackTraceElement element) {
|
||||
return !element.getClassName().startsWith(Objectify.class.getPackage().getName())
|
||||
&& !element.getClassName().startsWith(Ofy.class.getName());
|
||||
}}).get())));
|
||||
super(
|
||||
Joiner.on('\n')
|
||||
.join(
|
||||
String.format(
|
||||
"Timestamp inversion between transaction time (%s) and %s",
|
||||
transactionTime, problem),
|
||||
getFileAndLine(
|
||||
FluentIterable.from(new Exception().getStackTrace())
|
||||
.firstMatch(
|
||||
(StackTraceElement element) ->
|
||||
!element
|
||||
.getClassName()
|
||||
.startsWith(Objectify.class.getPackage().getName())
|
||||
&& !element.getClassName().startsWith(Ofy.class.getName()))
|
||||
.get())));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ package google.registry.model.ofy;
|
|||
|
||||
import static com.google.common.base.Functions.constant;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.collect.Maps.filterValues;
|
||||
import static com.google.common.collect.Maps.toMap;
|
||||
import static google.registry.model.ofy.CommitLogBucket.getArbitraryBucketId;
|
||||
|
@ -23,7 +24,6 @@ import static google.registry.model.ofy.ObjectifyService.ofy;
|
|||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.googlecode.objectify.Key;
|
||||
|
@ -88,9 +88,11 @@ class TransactionInfo {
|
|||
}
|
||||
|
||||
ImmutableSet<Object> getSaves() {
|
||||
return FluentIterable
|
||||
.from(changesBuilder.build().values())
|
||||
return changesBuilder
|
||||
.build()
|
||||
.values()
|
||||
.stream()
|
||||
.filter(Predicates.not(IS_DELETE))
|
||||
.toSet();
|
||||
.collect(toImmutableSet());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
package google.registry.model.poll;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static google.registry.util.CollectionUtils.forceEmptyToNull;
|
||||
import static google.registry.util.CollectionUtils.nullToEmpty;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
|
@ -24,6 +25,7 @@ import com.google.common.base.Converter;
|
|||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
import com.googlecode.objectify.annotation.EntitySubclass;
|
||||
|
@ -235,26 +237,48 @@ public abstract class PollMessage extends ImmutableObject
|
|||
|
||||
public Builder setResponseData(ImmutableList<? extends ResponseData> responseData) {
|
||||
FluentIterable<? extends ResponseData> iterable = FluentIterable.from(responseData);
|
||||
getInstance().contactPendingActionNotificationResponses = forceEmptyToNull(
|
||||
iterable.filter(ContactPendingActionNotificationResponse.class).toList());
|
||||
getInstance().contactTransferResponses = forceEmptyToNull(
|
||||
iterable.filter(ContactTransferResponse.class).toList());
|
||||
getInstance().domainPendingActionNotificationResponses = forceEmptyToNull(
|
||||
iterable.filter(DomainPendingActionNotificationResponse.class).toList());
|
||||
getInstance().domainTransferResponses = forceEmptyToNull(
|
||||
iterable.filter(DomainTransferResponse.class).toList());
|
||||
getInstance().hostPendingActionNotificationResponses = forceEmptyToNull(
|
||||
iterable.filter(HostPendingActionNotificationResponse.class).toList());
|
||||
getInstance().contactPendingActionNotificationResponses =
|
||||
forceEmptyToNull(
|
||||
Streams.stream(iterable)
|
||||
.filter(ContactPendingActionNotificationResponse.class::isInstance)
|
||||
.map(ContactPendingActionNotificationResponse.class::cast)
|
||||
.collect(toImmutableList()));
|
||||
getInstance().contactTransferResponses =
|
||||
forceEmptyToNull(
|
||||
Streams.stream(iterable)
|
||||
.filter(ContactTransferResponse.class::isInstance)
|
||||
.map(ContactTransferResponse.class::cast)
|
||||
.collect(toImmutableList()));
|
||||
getInstance().domainPendingActionNotificationResponses =
|
||||
forceEmptyToNull(
|
||||
Streams.stream(iterable)
|
||||
.filter(DomainPendingActionNotificationResponse.class::isInstance)
|
||||
.map(DomainPendingActionNotificationResponse.class::cast)
|
||||
.collect(toImmutableList()));
|
||||
getInstance().domainTransferResponses =
|
||||
forceEmptyToNull(
|
||||
Streams.stream(iterable)
|
||||
.filter(DomainTransferResponse.class::isInstance)
|
||||
.map(DomainTransferResponse.class::cast)
|
||||
.collect(toImmutableList()));
|
||||
getInstance().hostPendingActionNotificationResponses =
|
||||
forceEmptyToNull(
|
||||
Streams.stream(iterable)
|
||||
.filter(HostPendingActionNotificationResponse.class::isInstance)
|
||||
.map(HostPendingActionNotificationResponse.class::cast)
|
||||
.collect(toImmutableList()));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setResponseExtensions(
|
||||
ImmutableList<? extends ResponseExtension> responseExtensions) {
|
||||
getInstance().launchInfoResponseExtension = FluentIterable
|
||||
.from(responseExtensions)
|
||||
.filter(LaunchInfoResponseExtension.class)
|
||||
.first()
|
||||
.orNull();
|
||||
getInstance().launchInfoResponseExtension =
|
||||
responseExtensions
|
||||
.stream()
|
||||
.filter(LaunchInfoResponseExtension.class::isInstance)
|
||||
.map(LaunchInfoResponseExtension.class::cast)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import static com.google.common.base.Predicates.in;
|
|||
import static com.google.common.base.Predicates.notNull;
|
||||
import static com.google.common.base.Strings.emptyToNull;
|
||||
import static com.google.common.base.Strings.nullToEmpty;
|
||||
import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;
|
||||
import static com.google.common.collect.Sets.immutableEnumSet;
|
||||
import static com.google.common.io.BaseEncoding.base64;
|
||||
import static google.registry.config.RegistryConfig.getDefaultRegistrarReferralUrl;
|
||||
|
@ -35,13 +36,13 @@ import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
|||
import static google.registry.util.X509Utils.getCertificateHash;
|
||||
import static google.registry.util.X509Utils.loadCertificate;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static java.util.Comparator.comparing;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
@ -50,6 +51,7 @@ import com.google.common.collect.ImmutableSortedSet;
|
|||
import com.google.common.collect.Ordering;
|
||||
import com.google.common.collect.Range;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.re2j.Pattern;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.Work;
|
||||
|
@ -193,12 +195,9 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
|
|||
* Compare two instances of {@link RegistrarContact} by their email addresses lexicographically.
|
||||
*/
|
||||
private static final Comparator<RegistrarContact> CONTACT_EMAIL_COMPARATOR =
|
||||
new Comparator<RegistrarContact>() {
|
||||
@Override
|
||||
public int compare(RegistrarContact rc1, RegistrarContact rc2) {
|
||||
return rc1.getEmailAddress().compareTo(rc2.getEmailAddress());
|
||||
}
|
||||
};
|
||||
comparing(
|
||||
(RegistrarContact arg) -> arg.getEmailAddress(),
|
||||
(String leftProperty, String rightProperty) -> leftProperty.compareTo(rightProperty));
|
||||
|
||||
/**
|
||||
* A caching {@link Supplier} of a clientId to {@link Registrar} map.
|
||||
|
@ -207,19 +206,21 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
|
|||
* query inside an unrelated client-affecting transaction.
|
||||
*/
|
||||
private static final Supplier<ImmutableMap<String, Registrar>> CACHE_BY_CLIENT_ID =
|
||||
memoizeWithShortExpiration(new Supplier<ImmutableMap<String, Registrar>>() {
|
||||
@Override
|
||||
public ImmutableMap<String, Registrar> get() {
|
||||
return ofy().doTransactionless(new Work<ImmutableMap<String, Registrar>>() {
|
||||
@Override
|
||||
public ImmutableMap<String, Registrar> run() {
|
||||
ImmutableMap.Builder<String, Registrar> builder = new ImmutableMap.Builder<>();
|
||||
for (Registrar registrar : loadAll()) {
|
||||
builder.put(registrar.getClientId(), registrar);
|
||||
}
|
||||
return builder.build();
|
||||
}});
|
||||
}});
|
||||
memoizeWithShortExpiration(
|
||||
() ->
|
||||
ofy()
|
||||
.doTransactionless(
|
||||
new Work<ImmutableMap<String, Registrar>>() {
|
||||
@Override
|
||||
public ImmutableMap<String, Registrar> run() {
|
||||
ImmutableMap.Builder<String, Registrar> builder =
|
||||
new ImmutableMap.Builder<>();
|
||||
for (Registrar registrar : loadAll()) {
|
||||
builder.put(registrar.getClientId(), registrar);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
}));
|
||||
|
||||
@Parent
|
||||
Key<EntityGroupRoot> parent = getCrossTldKey();
|
||||
|
@ -421,14 +422,13 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
|
|||
BillingMethod billingMethod;
|
||||
|
||||
@NonFinalForTesting
|
||||
private static Supplier<byte[]> saltSupplier = new Supplier<byte[]>() {
|
||||
@Override
|
||||
public byte[] get() {
|
||||
// There are 32 bytes in a sha-256 hash, and the salt should generally be the same size.
|
||||
byte[] salt = new byte[32];
|
||||
new SecureRandom().nextBytes(salt);
|
||||
return salt;
|
||||
}};
|
||||
private static Supplier<byte[]> saltSupplier =
|
||||
() -> {
|
||||
// There are 32 bytes in a sha-256 hash, and the salt should generally be the same size.
|
||||
byte[] salt = new byte[32];
|
||||
new SecureRandom().nextBytes(salt);
|
||||
return salt;
|
||||
};
|
||||
|
||||
public String getClientId() {
|
||||
return clientIdentifier;
|
||||
|
@ -576,9 +576,9 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
|
|||
* address.
|
||||
*/
|
||||
public ImmutableSortedSet<RegistrarContact> getContacts() {
|
||||
return FluentIterable.from(getContactsIterable())
|
||||
return Streams.stream(getContactsIterable())
|
||||
.filter(notNull())
|
||||
.toSortedSet(CONTACT_EMAIL_COMPARATOR);
|
||||
.collect(toImmutableSortedSet(CONTACT_EMAIL_COMPARATOR));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -586,16 +586,10 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
|
|||
* their email address.
|
||||
*/
|
||||
public ImmutableSortedSet<RegistrarContact> getContactsOfType(final RegistrarContact.Type type) {
|
||||
return FluentIterable.from(getContactsIterable())
|
||||
return Streams.stream(getContactsIterable())
|
||||
.filter(notNull())
|
||||
.filter(
|
||||
new Predicate<RegistrarContact>() {
|
||||
@Override
|
||||
public boolean apply(@Nullable RegistrarContact contact) {
|
||||
return contact.getTypes().contains(type);
|
||||
}
|
||||
})
|
||||
.toSortedSet(CONTACT_EMAIL_COMPARATOR);
|
||||
.filter((@Nullable RegistrarContact contact) -> contact.getTypes().contains(type))
|
||||
.collect(toImmutableSortedSet(CONTACT_EMAIL_COMPARATOR));
|
||||
}
|
||||
|
||||
private Iterable<RegistrarContact> getContactsIterable() {
|
||||
|
|
|
@ -16,17 +16,17 @@ package google.registry.model.registrar;
|
|||
|
||||
import static com.google.common.base.Functions.toStringFunction;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.collect.Iterables.transform;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.collect.Sets.difference;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableSortedCopy;
|
||||
import static google.registry.util.ObjectifyUtils.OBJECTS_TO_KEYS;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
import com.google.common.base.Enums;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.VoidWork;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
|
@ -141,7 +141,9 @@ public class RegistrarContact extends ImmutableObject implements Jsonifiable {
|
|||
}
|
||||
|
||||
public static ImmutableSet<Type> typesFromStrings(Iterable<String> typeNames) {
|
||||
return FluentIterable.from(typeNames).transform(Enums.stringConverter(Type.class)).toSet();
|
||||
return Streams.stream(typeNames)
|
||||
.map(Enums.stringConverter(Type.class))
|
||||
.collect(toImmutableSet());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -154,15 +156,25 @@ public class RegistrarContact extends ImmutableObject implements Jsonifiable {
|
|||
*/
|
||||
public static void updateContacts(
|
||||
final Registrar registrar, final Set<RegistrarContact> contacts) {
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().delete().keys(difference(
|
||||
ImmutableSet.copyOf(
|
||||
ofy().load().type(RegistrarContact.class).ancestor(registrar).keys()),
|
||||
FluentIterable.from(contacts).transform(OBJECTS_TO_KEYS).toSet()));
|
||||
ofy().save().entities(contacts);
|
||||
}});
|
||||
ofy()
|
||||
.transact(
|
||||
new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy()
|
||||
.delete()
|
||||
.keys(
|
||||
difference(
|
||||
ImmutableSet.copyOf(
|
||||
ofy()
|
||||
.load()
|
||||
.type(RegistrarContact.class)
|
||||
.ancestor(registrar)
|
||||
.keys()),
|
||||
contacts.stream().map(OBJECTS_TO_KEYS).collect(toImmutableSet())));
|
||||
ofy().save().entities(contacts);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Key<Registrar> getParent() {
|
||||
|
@ -260,7 +272,7 @@ public class RegistrarContact extends ImmutableObject implements Jsonifiable {
|
|||
.put("emailAddress", emailAddress)
|
||||
.put("phoneNumber", phoneNumber)
|
||||
.put("faxNumber", faxNumber)
|
||||
.put("types", Joiner.on(',').join(transform(getTypes(), toStringFunction())))
|
||||
.put("types", getTypes().stream().map(toStringFunction()).collect(joining(",")))
|
||||
.put("visibleInWhoisAsAdmin", visibleInWhoisAsAdmin)
|
||||
.put("visibleInWhoisAsTech", visibleInWhoisAsTech)
|
||||
.put("visibleInDomainWhoisAsAbuse", visibleInDomainWhoisAsAbuse)
|
||||
|
|
|
@ -19,6 +19,7 @@ import static com.google.common.base.Predicates.equalTo;
|
|||
import static com.google.common.base.Predicates.in;
|
||||
import static com.google.common.base.Predicates.not;
|
||||
import static com.google.common.base.Strings.emptyToNull;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.collect.Maps.filterValues;
|
||||
import static google.registry.model.CacheUtils.memoizeWithShortExpiration;
|
||||
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
|
@ -28,9 +29,9 @@ import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
|||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.common.net.InternetDomainName;
|
||||
import com.googlecode.objectify.Work;
|
||||
import google.registry.model.registry.Registry.TldType;
|
||||
|
@ -50,19 +51,22 @@ public final class Registries {
|
|||
* query inside an unrelated client-affecting transaction.
|
||||
*/
|
||||
private static Supplier<ImmutableMap<String, TldType>> createFreshCache() {
|
||||
return memoizeWithShortExpiration(new Supplier<ImmutableMap<String, TldType>>() {
|
||||
@Override
|
||||
public ImmutableMap<String, TldType> get() {
|
||||
return ofy().doTransactionless(new Work<ImmutableMap<String, TldType>>() {
|
||||
@Override
|
||||
public ImmutableMap<String, TldType> run() {
|
||||
ImmutableMap.Builder<String, TldType> builder = new ImmutableMap.Builder<>();
|
||||
for (Registry registry : ofy().load().type(Registry.class).ancestor(getCrossTldKey())) {
|
||||
builder.put(registry.getTldStr(), registry.getTldType());
|
||||
}
|
||||
return builder.build();
|
||||
}});
|
||||
}});
|
||||
return memoizeWithShortExpiration(
|
||||
() ->
|
||||
ofy()
|
||||
.doTransactionless(
|
||||
new Work<ImmutableMap<String, TldType>>() {
|
||||
@Override
|
||||
public ImmutableMap<String, TldType> run() {
|
||||
ImmutableMap.Builder<String, TldType> builder =
|
||||
new ImmutableMap.Builder<>();
|
||||
for (Registry registry :
|
||||
ofy().load().type(Registry.class).ancestor(getCrossTldKey())) {
|
||||
builder.put(registry.getTldStr(), registry.getTldType());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
/** Manually reset the static cache backing the methods on this class. */
|
||||
|
@ -93,7 +97,8 @@ public final class Registries {
|
|||
for (String tld : tlds) {
|
||||
checkArgumentNotNull(emptyToNull(tld), "Null or empty TLD specified");
|
||||
}
|
||||
ImmutableSet<String> badTlds = FluentIterable.from(tlds).filter(not(in(getTlds()))).toSet();
|
||||
ImmutableSet<String> badTlds =
|
||||
Streams.stream(tlds).filter(not(in(getTlds()))).collect(toImmutableSet());
|
||||
checkArgument(badTlds.isEmpty(), "TLDs do not exist: %s", Joiner.on(", ").join(badTlds));
|
||||
return tlds;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkArgument;
|
|||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Predicates.equalTo;
|
||||
import static com.google.common.base.Predicates.not;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static google.registry.config.RegistryConfig.getSingletonCacheRefreshDuration;
|
||||
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
|
@ -34,7 +35,6 @@ import com.google.common.base.Predicate;
|
|||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
@ -799,15 +799,12 @@ public class Registry extends ImmutableObject implements Buildable {
|
|||
}
|
||||
}
|
||||
ImmutableSet<Entry<String, Collection<String>>> conflicts =
|
||||
FluentIterable.from(allAuthCodes.asMap().entrySet())
|
||||
.filter(
|
||||
new Predicate<Entry<String, Collection<String>>>() {
|
||||
@Override
|
||||
public boolean apply(Entry<String, Collection<String>> entry) {
|
||||
return entry.getValue().size() > 1;
|
||||
}
|
||||
})
|
||||
.toSet();
|
||||
allAuthCodes
|
||||
.asMap()
|
||||
.entrySet()
|
||||
.stream()
|
||||
.filter((Entry<String, Collection<String>> entry) -> entry.getValue().size() > 1)
|
||||
.collect(toImmutableSet());
|
||||
checkArgument(
|
||||
conflicts.isEmpty(),
|
||||
"Cannot set reserved lists because of auth code conflicts for labels: %s",
|
||||
|
@ -837,14 +834,7 @@ public class Registry extends ImmutableObject implements Buildable {
|
|||
ImmutableSortedMap<DateTime, Money> renewCostsMap) {
|
||||
checkArgumentNotNull(renewCostsMap, "Renew billing costs map cannot be null");
|
||||
checkArgument(
|
||||
Iterables.all(
|
||||
renewCostsMap.values(),
|
||||
new Predicate<Money>() {
|
||||
@Override
|
||||
public boolean apply(Money amount) {
|
||||
return amount.isPositiveOrZero();
|
||||
}
|
||||
}),
|
||||
renewCostsMap.values().stream().allMatch(Money::isPositiveOrZero),
|
||||
"Renew billing cost cannot be negative");
|
||||
getInstance().renewBillingCostTransitions =
|
||||
TimedTransitionProperty.fromValueMap(renewCostsMap, BillingCostTransition.class);
|
||||
|
@ -855,14 +845,7 @@ public class Registry extends ImmutableObject implements Buildable {
|
|||
public Builder setEapFeeSchedule(ImmutableSortedMap<DateTime, Money> eapFeeSchedule) {
|
||||
checkArgumentNotNull(eapFeeSchedule, "EAP schedule map cannot be null");
|
||||
checkArgument(
|
||||
Iterables.all(
|
||||
eapFeeSchedule.values(),
|
||||
new Predicate<Money>() {
|
||||
@Override
|
||||
public boolean apply(Money amount) {
|
||||
return amount.isPositiveOrZero();
|
||||
}
|
||||
}),
|
||||
eapFeeSchedule.values().stream().allMatch(Money::isPositiveOrZero),
|
||||
"EAP fee cannot be negative");
|
||||
getInstance().eapFeeSchedule =
|
||||
TimedTransitionProperty.fromValueMap(eapFeeSchedule, BillingCostTransition.class);
|
||||
|
@ -939,17 +922,12 @@ public class Registry extends ImmutableObject implements Buildable {
|
|||
instance.getServerStatusChangeCost().getCurrencyUnit().equals(instance.currency),
|
||||
"Server status change cost must be in the registry's currency");
|
||||
Predicate<Money> currencyCheck =
|
||||
new Predicate<Money>() {
|
||||
@Override
|
||||
public boolean apply(Money money) {
|
||||
return money.getCurrencyUnit().equals(instance.currency);
|
||||
}
|
||||
};
|
||||
(Money money) -> money.getCurrencyUnit().equals(instance.currency);
|
||||
checkArgument(
|
||||
Iterables.all(instance.getRenewBillingCostTransitions().values(), currencyCheck),
|
||||
instance.getRenewBillingCostTransitions().values().stream().allMatch(currencyCheck),
|
||||
"Renew cost must be in the registry's currency");
|
||||
checkArgument(
|
||||
Iterables.all(instance.eapFeeSchedule.toValueMap().values(), currencyCheck),
|
||||
instance.eapFeeSchedule.toValueMap().values().stream().allMatch(currencyCheck),
|
||||
"All EAP fees must be in the registry's currency");
|
||||
checkArgumentNotNull(
|
||||
instance.pricingEngineClassName, "All registries must have a configured pricing engine");
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
package google.registry.model.registry.label;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.collect.Iterables.partition;
|
||||
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
|
@ -30,12 +31,11 @@ import static org.joda.time.DateTimeZone.UTC;
|
|||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.cache.CacheLoader.InvalidCacheLoadException;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.VoidWork;
|
||||
import com.googlecode.objectify.Work;
|
||||
|
@ -202,15 +202,9 @@ public final class PremiumListUtils {
|
|||
@VisibleForTesting
|
||||
public static ImmutableSet<PremiumListEntry> parentPremiumListEntriesOnRevision(
|
||||
Iterable<PremiumListEntry> entries, final Key<PremiumListRevision> revisionKey) {
|
||||
return FluentIterable.from(entries)
|
||||
.transform(
|
||||
new Function<PremiumListEntry, PremiumListEntry>() {
|
||||
@Override
|
||||
public PremiumListEntry apply(PremiumListEntry entry) {
|
||||
return entry.asBuilder().setParent(revisionKey).build();
|
||||
}
|
||||
})
|
||||
.toSet();
|
||||
return Streams.stream(entries)
|
||||
.map((PremiumListEntry entry) -> entry.asBuilder().setParent(revisionKey).build())
|
||||
.collect(toImmutableSet());
|
||||
}
|
||||
|
||||
/** Deletes the PremiumList and all of its child entities. */
|
||||
|
|
|
@ -17,6 +17,7 @@ package google.registry.model.registry.label;
|
|||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.collect.Iterables.getOnlyElement;
|
||||
import static google.registry.config.RegistryConfig.getDomainLabelListCacheDuration;
|
||||
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
|
@ -28,14 +29,12 @@ import static google.registry.util.CollectionUtils.nullToEmpty;
|
|||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.net.InternetDomainName;
|
||||
|
@ -217,15 +216,10 @@ public final class ReservedList
|
|||
if (label.length() == 0) {
|
||||
return ImmutableSet.of(FULLY_BLOCKED);
|
||||
}
|
||||
return FluentIterable.from(getReservedListEntries(label, tld))
|
||||
.transform(
|
||||
new Function<ReservedListEntry, ReservationType>() {
|
||||
@Override
|
||||
public ReservationType apply(ReservedListEntry reservedListEntry) {
|
||||
return reservedListEntry.reservationType;
|
||||
}
|
||||
})
|
||||
.toSet();
|
||||
return getReservedListEntries(label, tld)
|
||||
.stream()
|
||||
.map((ReservedListEntry reservedListEntry) -> reservedListEntry.reservationType)
|
||||
.collect(toImmutableSet());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,7 +25,6 @@ import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
|||
import static google.registry.util.DateTimeUtils.isBeforeOrAt;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
@ -93,31 +92,36 @@ public class SignedMarkRevocationList extends ImmutableObject {
|
|||
* single {@link SignedMarkRevocationList} object.
|
||||
*/
|
||||
private static final Supplier<SignedMarkRevocationList> CACHE =
|
||||
memoizeWithShortExpiration(new Supplier<SignedMarkRevocationList>() {
|
||||
@Override
|
||||
public SignedMarkRevocationList get() {
|
||||
// Open a new transactional read even if we are in a transaction currently.
|
||||
return ofy().transactNewReadOnly(new Work<SignedMarkRevocationList>() {
|
||||
@Override
|
||||
public SignedMarkRevocationList run() {
|
||||
Iterable<SignedMarkRevocationList> shards = ofy()
|
||||
.load()
|
||||
.type(SignedMarkRevocationList.class)
|
||||
.ancestor(getCrossTldKey());
|
||||
DateTime creationTime =
|
||||
isEmpty(shards)
|
||||
? START_OF_TIME
|
||||
: checkNotNull(Iterables.get(shards, 0).creationTime, "creationTime");
|
||||
ImmutableMap.Builder<String, DateTime> revokes = new ImmutableMap.Builder<>();
|
||||
for (SignedMarkRevocationList shard : shards) {
|
||||
revokes.putAll(shard.revokes);
|
||||
checkState(
|
||||
creationTime.equals(shard.creationTime),
|
||||
"Inconsistent creation times: %s vs. %s", creationTime, shard.creationTime);
|
||||
}
|
||||
return create(creationTime, revokes.build());
|
||||
}});
|
||||
}});
|
||||
memoizeWithShortExpiration(
|
||||
() ->
|
||||
ofy()
|
||||
.transactNewReadOnly(
|
||||
new Work<SignedMarkRevocationList>() {
|
||||
@Override
|
||||
public SignedMarkRevocationList run() {
|
||||
Iterable<SignedMarkRevocationList> shards =
|
||||
ofy()
|
||||
.load()
|
||||
.type(SignedMarkRevocationList.class)
|
||||
.ancestor(getCrossTldKey());
|
||||
DateTime creationTime =
|
||||
isEmpty(shards)
|
||||
? START_OF_TIME
|
||||
: checkNotNull(
|
||||
Iterables.get(shards, 0).creationTime, "creationTime");
|
||||
ImmutableMap.Builder<String, DateTime> revokes =
|
||||
new ImmutableMap.Builder<>();
|
||||
for (SignedMarkRevocationList shard : shards) {
|
||||
revokes.putAll(shard.revokes);
|
||||
checkState(
|
||||
creationTime.equals(shard.creationTime),
|
||||
"Inconsistent creation times: %s vs. %s",
|
||||
creationTime,
|
||||
shard.creationTime);
|
||||
}
|
||||
return create(creationTime, revokes.build());
|
||||
}
|
||||
}));
|
||||
|
||||
/** Return a single logical instance that combines all Datastore shards. */
|
||||
public static SignedMarkRevocationList get() {
|
||||
|
@ -154,25 +158,34 @@ public class SignedMarkRevocationList extends ImmutableObject {
|
|||
|
||||
/** Save this list to Datastore in sharded form. Returns {@code this}. */
|
||||
public SignedMarkRevocationList save() {
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().deleteWithoutBackup().keys(ofy()
|
||||
.load()
|
||||
.type(SignedMarkRevocationList.class)
|
||||
.ancestor(getCrossTldKey())
|
||||
.keys());
|
||||
ofy().saveWithoutBackup().entities(FluentIterable
|
||||
.from(CollectionUtils.partitionMap(revokes, SHARD_SIZE))
|
||||
.transform(new Function<ImmutableMap<String, DateTime>, SignedMarkRevocationList>() {
|
||||
ofy()
|
||||
.transact(
|
||||
new VoidWork() {
|
||||
@Override
|
||||
public SignedMarkRevocationList apply(ImmutableMap<String, DateTime> shardRevokes) {
|
||||
SignedMarkRevocationList shard = create(creationTime, shardRevokes);
|
||||
shard.id = allocateId();
|
||||
shard.isShard = true; // Avoid the exception in disallowUnshardedSaves().
|
||||
return shard;
|
||||
}}));
|
||||
}});
|
||||
public void vrun() {
|
||||
ofy()
|
||||
.deleteWithoutBackup()
|
||||
.keys(
|
||||
ofy()
|
||||
.load()
|
||||
.type(SignedMarkRevocationList.class)
|
||||
.ancestor(getCrossTldKey())
|
||||
.keys());
|
||||
ofy()
|
||||
.saveWithoutBackup()
|
||||
.entities(
|
||||
FluentIterable.from(CollectionUtils.partitionMap(revokes, SHARD_SIZE))
|
||||
.transform(
|
||||
(ImmutableMap<String, DateTime> shardRevokes) -> {
|
||||
SignedMarkRevocationList shard =
|
||||
create(creationTime, shardRevokes);
|
||||
shard.id = allocateId();
|
||||
shard.isShard =
|
||||
true; // Avoid the exception in disallowUnshardedSaves().
|
||||
return shard;
|
||||
}));
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ import static google.registry.model.ofy.ObjectifyService.ofy;
|
|||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.googlecode.objectify.Key;
|
||||
|
@ -96,54 +95,47 @@ public class ClaimsListShard extends ImmutableObject {
|
|||
private static final Retrier LOADER_RETRIER = new Retrier(new SystemSleeper(), 2);
|
||||
|
||||
private static final Callable<ClaimsListShard> LOADER_CALLABLE =
|
||||
new Callable<ClaimsListShard>() {
|
||||
@Override
|
||||
public ClaimsListShard call() throws Exception {
|
||||
// Find the most recent revision.
|
||||
Key<ClaimsListRevision> revisionKey = getCurrentRevision();
|
||||
() -> {
|
||||
// Find the most recent revision.
|
||||
Key<ClaimsListRevision> revisionKey = getCurrentRevision();
|
||||
|
||||
Map<String, String> combinedLabelsToKeys = new HashMap<>();
|
||||
DateTime creationTime = START_OF_TIME;
|
||||
if (revisionKey != null) {
|
||||
// Grab all of the keys for the shards that belong to the current revision.
|
||||
final List<Key<ClaimsListShard>> shardKeys =
|
||||
ofy().load().type(ClaimsListShard.class).ancestor(revisionKey).keys().list();
|
||||
Map<String, String> combinedLabelsToKeys = new HashMap<>();
|
||||
DateTime creationTime = START_OF_TIME;
|
||||
if (revisionKey != null) {
|
||||
// Grab all of the keys for the shards that belong to the current revision.
|
||||
final List<Key<ClaimsListShard>> shardKeys =
|
||||
ofy().load().type(ClaimsListShard.class).ancestor(revisionKey).keys().list();
|
||||
|
||||
// Load all of the shards concurrently, each in a separate transaction.
|
||||
List<ClaimsListShard> shards =
|
||||
Concurrent.transform(
|
||||
shardKeys,
|
||||
new Function<Key<ClaimsListShard>, ClaimsListShard>() {
|
||||
@Override
|
||||
public ClaimsListShard apply(final Key<ClaimsListShard> key) {
|
||||
return ofy()
|
||||
.transactNewReadOnly(
|
||||
new Work<ClaimsListShard>() {
|
||||
@Override
|
||||
public ClaimsListShard run() {
|
||||
ClaimsListShard claimsListShard = ofy().load().key(key).now();
|
||||
checkState(
|
||||
claimsListShard != null,
|
||||
"Key not found when loading claims list shards.");
|
||||
return claimsListShard;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// Load all of the shards concurrently, each in a separate transaction.
|
||||
List<ClaimsListShard> shards =
|
||||
Concurrent.transform(
|
||||
shardKeys,
|
||||
(final Key<ClaimsListShard> key) ->
|
||||
ofy()
|
||||
.transactNewReadOnly(
|
||||
new Work<ClaimsListShard>() {
|
||||
@Override
|
||||
public ClaimsListShard run() {
|
||||
ClaimsListShard claimsListShard = ofy().load().key(key).now();
|
||||
checkState(
|
||||
claimsListShard != null,
|
||||
"Key not found when loading claims list shards.");
|
||||
return claimsListShard;
|
||||
}
|
||||
}));
|
||||
|
||||
// Combine the shards together and return the concatenated ClaimsList.
|
||||
if (!shards.isEmpty()) {
|
||||
creationTime = shards.get(0).creationTime;
|
||||
for (ClaimsListShard shard : shards) {
|
||||
combinedLabelsToKeys.putAll(shard.labelsToKeys);
|
||||
checkState(
|
||||
creationTime.equals(shard.creationTime),
|
||||
"Inconsistent claims list shard creation times.");
|
||||
}
|
||||
// Combine the shards together and return the concatenated ClaimsList.
|
||||
if (!shards.isEmpty()) {
|
||||
creationTime = shards.get(0).creationTime;
|
||||
for (ClaimsListShard shard : shards) {
|
||||
combinedLabelsToKeys.putAll(shard.labelsToKeys);
|
||||
checkState(
|
||||
creationTime.equals(shard.creationTime),
|
||||
"Inconsistent claims list shard creation times.");
|
||||
}
|
||||
}
|
||||
return create(creationTime, ImmutableMap.copyOf(combinedLabelsToKeys));
|
||||
}
|
||||
return create(creationTime, ImmutableMap.copyOf(combinedLabelsToKeys));
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -152,12 +144,7 @@ public class ClaimsListShard extends ImmutableObject {
|
|||
*/
|
||||
private static final Supplier<ClaimsListShard> CACHE =
|
||||
memoizeWithShortExpiration(
|
||||
new Supplier<ClaimsListShard>() {
|
||||
@Override
|
||||
public ClaimsListShard get() {
|
||||
return LOADER_RETRIER.callWithRetry(LOADER_CALLABLE, IllegalStateException.class);
|
||||
}
|
||||
});
|
||||
() -> LOADER_RETRIER.callWithRetry(LOADER_CALLABLE, IllegalStateException.class));
|
||||
|
||||
public DateTime getCreationTime() {
|
||||
return creationTime;
|
||||
|
@ -186,20 +173,21 @@ public class ClaimsListShard extends ImmutableObject {
|
|||
final Key<ClaimsListRevision> parentKey = ClaimsListRevision.createKey();
|
||||
|
||||
// Save the ClaimsList shards in separate transactions.
|
||||
Concurrent.transform(CollectionUtils.partitionMap(labelsToKeys, shardSize),
|
||||
new Function<ImmutableMap<String, String>, ClaimsListShard>() {
|
||||
@Override
|
||||
public ClaimsListShard apply(final ImmutableMap<String, String> labelsToKeysShard) {
|
||||
return ofy().transactNew(new Work<ClaimsListShard>() {
|
||||
@Override
|
||||
public ClaimsListShard run() {
|
||||
ClaimsListShard shard = create(creationTime, labelsToKeysShard);
|
||||
shard.isShard = true;
|
||||
shard.parent = parentKey;
|
||||
ofy().saveWithoutBackup().entity(shard);
|
||||
return shard;
|
||||
}});
|
||||
}});
|
||||
Concurrent.transform(
|
||||
CollectionUtils.partitionMap(labelsToKeys, shardSize),
|
||||
(final ImmutableMap<String, String> labelsToKeysShard) ->
|
||||
ofy()
|
||||
.transactNew(
|
||||
new Work<ClaimsListShard>() {
|
||||
@Override
|
||||
public ClaimsListShard run() {
|
||||
ClaimsListShard shard = create(creationTime, labelsToKeysShard);
|
||||
shard.isShard = true;
|
||||
shard.parent = parentKey;
|
||||
ofy().saveWithoutBackup().entity(shard);
|
||||
return shard;
|
||||
}
|
||||
}));
|
||||
|
||||
// Persist the new revision, thus causing the newly created shards to go live.
|
||||
ofy().transactNew(new VoidWork() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue