mirror of
https://github.com/google/nomulus.git
synced 2025-07-20 09:46:03 +02:00
Move premium list static helper methods into their own class
It was kind of messy having all of that logic living alongside the entities themselves. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=148498024
This commit is contained in:
parent
388dd1055e
commit
ea4e471c04
12 changed files with 523 additions and 421 deletions
|
@ -17,7 +17,7 @@ package google.registry.model.pricing;
|
|||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Strings.emptyToNull;
|
||||
import static google.registry.model.registry.Registry.TldState.SUNRISE;
|
||||
import static google.registry.model.registry.label.PremiumList.getPremiumPrice;
|
||||
import static google.registry.model.registry.label.PremiumListUtils.getPremiumPrice;
|
||||
import static google.registry.model.registry.label.ReservationType.NAME_COLLISION;
|
||||
import static google.registry.model.registry.label.ReservedList.getReservation;
|
||||
import static google.registry.util.DomainNameUtils.getTldFromDomainName;
|
||||
|
|
|
@ -13,10 +13,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
package google.registry.model.registry.label;
|
||||
import static com.google.common.base.MoreObjects.firstNonNull;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.collect.Iterables.partition;
|
||||
import static com.google.common.hash.Funnels.unencodedCharsFunnel;
|
||||
import static google.registry.config.RegistryConfig.getDomainLabelListCacheDuration;
|
||||
import static google.registry.config.RegistryConfig.getSingletonCachePersistDuration;
|
||||
|
@ -28,20 +25,15 @@ import static google.registry.model.ofy.Ofy.RECOMMENDED_MEMCACHE_EXPIRATION;
|
|||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
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.CacheLoader.InvalidCacheLoadException;
|
||||
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.hash.BloomFilter;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.VoidWork;
|
||||
import com.googlecode.objectify.Work;
|
||||
import com.googlecode.objectify.annotation.Cache;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
|
@ -55,13 +47,11 @@ import google.registry.model.registry.Registry;
|
|||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* A premium list entity, persisted to Datastore, that is used to check domain label prices.
|
||||
|
@ -71,9 +61,6 @@ import org.joda.time.DateTime;
|
|||
@Cache(expirationSeconds = RECOMMENDED_MEMCACHE_EXPIRATION)
|
||||
public final class PremiumList extends BaseDomainLabelList<Money, PremiumList.PremiumListEntry> {
|
||||
|
||||
/** The number of premium list entry entities that are created and deleted per batch. */
|
||||
private static final int TRANSACTION_BATCH_SIZE = 200;
|
||||
|
||||
/** Stores the revision key for the set of currently used premium list entry entities. */
|
||||
Key<PremiumListRevision> revisionKey;
|
||||
|
||||
|
@ -139,7 +126,7 @@ public final class PremiumList extends BaseDomainLabelList<Money, PremiumList.Pr
|
|||
* <p>This is cached for a shorter duration because we need to periodically reload this entity to
|
||||
* check if a new revision has been published, and if so, then use that.
|
||||
*/
|
||||
private static final LoadingCache<String, PremiumList> cachePremiumLists =
|
||||
static final LoadingCache<String, PremiumList> cachePremiumLists =
|
||||
CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(getDomainLabelListCacheDuration().getMillis(), MILLISECONDS)
|
||||
.build(new CacheLoader<String, PremiumList>() {
|
||||
|
@ -163,7 +150,7 @@ public final class PremiumList extends BaseDomainLabelList<Money, PremiumList.Pr
|
|||
* {@link PremiumListRevision} is immutable and cannot ever be changed once created, so its cache
|
||||
* need not ever expire.
|
||||
*/
|
||||
private static final LoadingCache<Key<PremiumListRevision>, PremiumListRevision>
|
||||
static final LoadingCache<Key<PremiumListRevision>, PremiumListRevision>
|
||||
cachePremiumListRevisions =
|
||||
CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(getSingletonCachePersistDuration().getMillis(), MILLISECONDS)
|
||||
|
@ -214,67 +201,6 @@ public final class PremiumList extends BaseDomainLabelList<Money, PremiumList.Pr
|
|||
}});
|
||||
}});
|
||||
|
||||
/**
|
||||
* Returns the premium price for the specified label and registry, or absent if the label is not
|
||||
* premium.
|
||||
*/
|
||||
public static Optional<Money> getPremiumPrice(String label, Registry registry) {
|
||||
// If the registry has no configured premium list, then no labels are premium.
|
||||
if (registry.getPremiumList() == null) {
|
||||
return Optional.<Money> absent();
|
||||
}
|
||||
String listName = registry.getPremiumList().getName();
|
||||
Optional<PremiumList> optionalPremiumList = get(listName);
|
||||
checkState(optionalPremiumList.isPresent(), "Could not load premium list '%s'", listName);
|
||||
PremiumList premiumList = optionalPremiumList.get();
|
||||
PremiumListRevision revision;
|
||||
try {
|
||||
revision = cachePremiumListRevisions.get(premiumList.getRevisionKey());
|
||||
} catch (InvalidCacheLoadException | ExecutionException e) {
|
||||
throw new RuntimeException(
|
||||
"Could not load premium list revision " + premiumList.getRevisionKey(), e);
|
||||
}
|
||||
checkState(
|
||||
revision.probablePremiumLabels != null,
|
||||
"Probable premium labels bloom filter is null on revision '%s'",
|
||||
premiumList.getRevisionKey());
|
||||
|
||||
if (revision.probablePremiumLabels.mightContain(label)) {
|
||||
Key<PremiumListEntry> entryKey =
|
||||
Key.create(premiumList.getRevisionKey(), PremiumListEntry.class, label);
|
||||
try {
|
||||
Optional<PremiumListEntry> entry = cachePremiumListEntries.get(entryKey);
|
||||
return (entry.isPresent()) ? Optional.of(entry.get().getValue()) : Optional.<Money>absent();
|
||||
} catch (InvalidCacheLoadException | ExecutionException e) {
|
||||
throw new RuntimeException("Could not load premium list entry " + entryKey, e);
|
||||
}
|
||||
} else {
|
||||
return Optional.<Money>absent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and returns the entire premium list map.
|
||||
*
|
||||
* <p>This load operation is quite expensive for large premium lists because each premium list
|
||||
* entry is a separate Datastore entity, and loading them this way bypasses the in-memory caches.
|
||||
* Do not use this method if all you need to do is check the price of a small number of labels!
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public Map<String, PremiumListEntry> loadPremiumListEntries() {
|
||||
try {
|
||||
ImmutableMap.Builder<String, PremiumListEntry> entriesMap = new ImmutableMap.Builder<>();
|
||||
if (revisionKey != null) {
|
||||
for (PremiumListEntry entry : queryEntriesForCurrentRevision()) {
|
||||
entriesMap.put(entry.getLabel(), entry);
|
||||
}
|
||||
}
|
||||
return entriesMap.build();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not retrieve entries for premium list " + name, e);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public Key<PremiumListRevision> getRevisionKey() {
|
||||
return revisionKey;
|
||||
|
@ -291,11 +217,6 @@ public final class PremiumList extends BaseDomainLabelList<Money, PremiumList.Pr
|
|||
}
|
||||
}
|
||||
|
||||
/** Returns whether a PremiumList of the given name exists, bypassing the cache. */
|
||||
public static boolean exists(String name) {
|
||||
return ofy().load().key(Key.create(getCrossTldKey(), PremiumList.class, name)).now() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A premium list entry entity, persisted to Datastore. Each instance represents the price of a
|
||||
* single label on a given TLD.
|
||||
|
@ -361,124 +282,12 @@ public final class PremiumList extends BaseDomainLabelList<Money, PremiumList.Pr
|
|||
.build();
|
||||
}
|
||||
|
||||
public static PremiumList saveWithEntries(
|
||||
PremiumList premiumList, Iterable<String> premiumListLines) {
|
||||
return saveWithEntries(premiumList, premiumList.parse(premiumListLines));
|
||||
}
|
||||
|
||||
/** Re-parents the given {@link PremiumListEntry}s on the given {@link PremiumListRevision}. */
|
||||
public static ImmutableSet<PremiumListEntry> parentEntriesOnRevision(
|
||||
Iterable<PremiumListEntry> entries, final Key<PremiumListRevision> revisionKey) {
|
||||
return FluentIterable.from(firstNonNull(entries, ImmutableSet.of()))
|
||||
.transform(
|
||||
new Function<PremiumListEntry, PremiumListEntry>() {
|
||||
@Override
|
||||
public PremiumListEntry apply(PremiumListEntry entry) {
|
||||
return entry.asBuilder().setParent(revisionKey).build();
|
||||
}
|
||||
})
|
||||
.toSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists a new or updated PremiumList object and its descendant entities to Datastore.
|
||||
*
|
||||
* <p>The flow here is: save the new premium list entries parented on that revision entity,
|
||||
* save/update the PremiumList, and then delete the old premium list entries associated with the
|
||||
* old revision.
|
||||
*
|
||||
* <p>This is the only valid way to save these kinds of entities!
|
||||
*/
|
||||
public static PremiumList saveWithEntries(
|
||||
final PremiumList premiumList, ImmutableMap<String, PremiumListEntry> premiumListEntries) {
|
||||
final Optional<PremiumList> oldPremiumList = get(premiumList.getName());
|
||||
|
||||
// Create the new revision (with its bloom filter) and parent the entries on it.
|
||||
final PremiumListRevision newRevision =
|
||||
PremiumListRevision.create(premiumList, premiumListEntries.keySet());
|
||||
final Key<PremiumListRevision> newRevisionKey = Key.create(newRevision);
|
||||
ImmutableSet<PremiumListEntry> parentedEntries =
|
||||
parentEntriesOnRevision(
|
||||
firstNonNull(premiumListEntries.values(), ImmutableSet.of()), newRevisionKey);
|
||||
|
||||
// Save the new child entities in a series of transactions.
|
||||
for (final List<PremiumListEntry> batch : partition(parentedEntries, TRANSACTION_BATCH_SIZE)) {
|
||||
ofy().transactNew(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entities(batch);
|
||||
}});
|
||||
}
|
||||
|
||||
// Save the new PremiumList and revision itself.
|
||||
PremiumList updated = ofy().transactNew(new Work<PremiumList>() {
|
||||
@Override
|
||||
public PremiumList run() {
|
||||
DateTime now = ofy().getTransactionTime();
|
||||
// Assert that the premium list hasn't been changed since we started this process.
|
||||
PremiumList existing = ofy().load()
|
||||
.type(PremiumList.class)
|
||||
.parent(getCrossTldKey())
|
||||
.id(premiumList.getName())
|
||||
.now();
|
||||
checkState(
|
||||
Objects.equals(existing, oldPremiumList.orNull()),
|
||||
"PremiumList was concurrently edited");
|
||||
PremiumList newList = premiumList.asBuilder()
|
||||
.setLastUpdateTime(now)
|
||||
.setCreationTime(
|
||||
oldPremiumList.isPresent() ? oldPremiumList.get().creationTime : now)
|
||||
.setRevision(newRevisionKey)
|
||||
.build();
|
||||
ofy().save().entities(newList, newRevision);
|
||||
return newList;
|
||||
}});
|
||||
// Update the cache.
|
||||
cachePremiumLists.put(premiumList.getName(), updated);
|
||||
// Delete the entities under the old PremiumList.
|
||||
if (oldPremiumList.isPresent()) {
|
||||
oldPremiumList.get().deleteRevisionAndEntries();
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean refersToKey(Registry registry, Key<? extends BaseDomainLabelList<?, ?>> key) {
|
||||
return Objects.equals(registry.getPremiumList(), key);
|
||||
}
|
||||
|
||||
/** Deletes the PremiumList and all of its child entities. */
|
||||
public void delete() {
|
||||
ofy().transactNew(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().delete().entity(PremiumList.this);
|
||||
}});
|
||||
deleteRevisionAndEntries();
|
||||
cachePremiumLists.invalidate(name);
|
||||
}
|
||||
|
||||
private void deleteRevisionAndEntries() {
|
||||
if (revisionKey == null) {
|
||||
return;
|
||||
}
|
||||
for (final List<Key<PremiumListEntry>> batch : partition(
|
||||
queryEntriesForCurrentRevision().keys(),
|
||||
TRANSACTION_BATCH_SIZE)) {
|
||||
ofy().transactNew(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().delete().keys(batch);
|
||||
}});
|
||||
}
|
||||
ofy().transactNew(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().delete().key(revisionKey);
|
||||
}});
|
||||
}
|
||||
|
||||
private Query<PremiumListEntry> queryEntriesForCurrentRevision() {
|
||||
Query<PremiumListEntry> queryEntriesForCurrentRevision() {
|
||||
return ofy().load().type(PremiumListEntry.class).ancestor(revisionKey);
|
||||
}
|
||||
|
||||
|
|
234
java/google/registry/model/registry/label/PremiumListUtils.java
Normal file
234
java/google/registry/model/registry/label/PremiumListUtils.java
Normal file
|
@ -0,0 +1,234 @@
|
|||
// 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.registry.label;
|
||||
|
||||
import static com.google.common.base.MoreObjects.firstNonNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.collect.Iterables.partition;
|
||||
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.model.registry.label.PremiumList.cachePremiumListEntries;
|
||||
import static google.registry.model.registry.label.PremiumList.cachePremiumListRevisions;
|
||||
import static google.registry.model.registry.label.PremiumList.cachePremiumLists;
|
||||
|
||||
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.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.VoidWork;
|
||||
import com.googlecode.objectify.Work;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.model.registry.label.PremiumList.PremiumListEntry;
|
||||
import google.registry.model.registry.label.PremiumList.PremiumListRevision;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** Static helper methods for working with {@link PremiumList}s. */
|
||||
public final class PremiumListUtils {
|
||||
|
||||
/** The number of premium list entry entities that are created and deleted per batch. */
|
||||
static final int TRANSACTION_BATCH_SIZE = 200;
|
||||
|
||||
/**
|
||||
* Returns the premium price for the specified label and registry, or absent if the label is not
|
||||
* premium.
|
||||
*/
|
||||
public static Optional<Money> getPremiumPrice(String label, Registry registry) {
|
||||
// If the registry has no configured premium list, then no labels are premium.
|
||||
if (registry.getPremiumList() == null) {
|
||||
return Optional.<Money> absent();
|
||||
}
|
||||
String listName = registry.getPremiumList().getName();
|
||||
Optional<PremiumList> optionalPremiumList = PremiumList.get(listName);
|
||||
checkState(optionalPremiumList.isPresent(), "Could not load premium list '%s'", listName);
|
||||
PremiumList premiumList = optionalPremiumList.get();
|
||||
PremiumListRevision revision;
|
||||
try {
|
||||
revision = cachePremiumListRevisions.get(premiumList.getRevisionKey());
|
||||
} catch (InvalidCacheLoadException | ExecutionException e) {
|
||||
throw new RuntimeException(
|
||||
"Could not load premium list revision " + premiumList.getRevisionKey(), e);
|
||||
}
|
||||
checkState(
|
||||
revision.probablePremiumLabels != null,
|
||||
"Probable premium labels bloom filter is null on revision '%s'",
|
||||
premiumList.getRevisionKey());
|
||||
|
||||
if (revision.probablePremiumLabels.mightContain(label)) {
|
||||
Key<PremiumListEntry> entryKey =
|
||||
Key.create(premiumList.getRevisionKey(), PremiumListEntry.class, label);
|
||||
try {
|
||||
Optional<PremiumListEntry> entry = cachePremiumListEntries.get(entryKey);
|
||||
return (entry.isPresent()) ? Optional.of(entry.get().getValue()) : Optional.<Money>absent();
|
||||
} catch (InvalidCacheLoadException | ExecutionException e) {
|
||||
throw new RuntimeException("Could not load premium list entry " + entryKey, e);
|
||||
}
|
||||
} else {
|
||||
return Optional.<Money>absent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists a new or updated PremiumList object and its descendant entities to Datastore.
|
||||
*
|
||||
* <p>The flow here is: save the new premium list entries parented on that revision entity,
|
||||
* save/update the PremiumList, and then delete the old premium list entries associated with the
|
||||
* old revision.
|
||||
*
|
||||
* <p>This is the only valid way to save these kinds of entities!
|
||||
*/
|
||||
public static PremiumList savePremiumListAndEntries(
|
||||
final PremiumList premiumList,
|
||||
ImmutableMap<String, PremiumListEntry> premiumListEntries) {
|
||||
final Optional<PremiumList> oldPremiumList = PremiumList.get(premiumList.getName());
|
||||
|
||||
// Create the new revision (with its bloom filter) and parent the entries on it.
|
||||
final PremiumListRevision newRevision =
|
||||
PremiumListRevision.create(premiumList, premiumListEntries.keySet());
|
||||
final Key<PremiumListRevision> newRevisionKey = Key.create(newRevision);
|
||||
ImmutableSet<PremiumListEntry> parentedEntries =
|
||||
parentPremiumListEntriesOnRevision(
|
||||
firstNonNull(premiumListEntries.values(), ImmutableSet.of()), newRevisionKey);
|
||||
|
||||
// Save the new child entities in a series of transactions.
|
||||
for (final List<PremiumListEntry> batch :
|
||||
partition(parentedEntries, TRANSACTION_BATCH_SIZE)) {
|
||||
ofy().transactNew(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entities(batch);
|
||||
}});
|
||||
}
|
||||
|
||||
// Save the new PremiumList and revision itself.
|
||||
PremiumList updated = ofy().transactNew(new Work<PremiumList>() {
|
||||
@Override
|
||||
public PremiumList run() {
|
||||
DateTime now = ofy().getTransactionTime();
|
||||
// Assert that the premium list hasn't been changed since we started this process.
|
||||
PremiumList existing = ofy().load()
|
||||
.type(PremiumList.class)
|
||||
.parent(getCrossTldKey())
|
||||
.id(premiumList.getName())
|
||||
.now();
|
||||
checkState(
|
||||
Objects.equals(existing, oldPremiumList.orNull()),
|
||||
"PremiumList was concurrently edited");
|
||||
PremiumList newList = premiumList.asBuilder()
|
||||
.setLastUpdateTime(now)
|
||||
.setCreationTime(
|
||||
oldPremiumList.isPresent() ? oldPremiumList.get().creationTime : now)
|
||||
.setRevision(newRevisionKey)
|
||||
.build();
|
||||
ofy().save().entities(newList, newRevision);
|
||||
return newList;
|
||||
}});
|
||||
// Update the cache.
|
||||
cachePremiumLists.put(premiumList.getName(), updated);
|
||||
// Delete the entities under the old PremiumList.
|
||||
if (oldPremiumList.isPresent()) {
|
||||
deleteRevisionAndEntriesOfPremiumList(oldPremiumList.get());
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
public static PremiumList savePremiumListAndEntries(
|
||||
PremiumList premiumList, Iterable<String> premiumListLines) {
|
||||
return savePremiumListAndEntries(premiumList, premiumList.parse(premiumListLines));
|
||||
}
|
||||
|
||||
/** Re-parents the given {@link PremiumListEntry}s on the given {@link PremiumListRevision}. */
|
||||
public static ImmutableSet<PremiumListEntry> parentPremiumListEntriesOnRevision(
|
||||
Iterable<PremiumListEntry> entries, final Key<PremiumListRevision> revisionKey) {
|
||||
return FluentIterable.from(firstNonNull(entries, ImmutableSet.of()))
|
||||
.transform(
|
||||
new Function<PremiumListEntry, PremiumListEntry>() {
|
||||
@Override
|
||||
public PremiumListEntry apply(PremiumListEntry entry) {
|
||||
return entry.asBuilder().setParent(revisionKey).build();
|
||||
}
|
||||
})
|
||||
.toSet();
|
||||
}
|
||||
|
||||
/** Deletes the PremiumList and all of its child entities. */
|
||||
public static void deletePremiumList(final PremiumList premiumList) {
|
||||
ofy().transactNew(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().delete().entity(premiumList);
|
||||
}});
|
||||
deleteRevisionAndEntriesOfPremiumList(premiumList);
|
||||
cachePremiumLists.invalidate(premiumList.getName());
|
||||
}
|
||||
|
||||
static void deleteRevisionAndEntriesOfPremiumList(final PremiumList premiumList) {
|
||||
if (premiumList.getRevisionKey() == null) {
|
||||
return;
|
||||
}
|
||||
for (final List<Key<PremiumListEntry>> batch : partition(
|
||||
premiumList.queryEntriesForCurrentRevision().keys(),
|
||||
TRANSACTION_BATCH_SIZE)) {
|
||||
ofy().transactNew(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().delete().keys(batch);
|
||||
}});
|
||||
}
|
||||
ofy().transactNew(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().delete().key(premiumList.getRevisionKey());
|
||||
}});
|
||||
}
|
||||
|
||||
/** Returns whether a PremiumList of the given name exists, bypassing the cache. */
|
||||
public static boolean doesPremiumListExist(String name) {
|
||||
return ofy().load().key(Key.create(getCrossTldKey(), PremiumList.class, name)).now() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and returns the entire premium list map.
|
||||
*
|
||||
* <p>This load operation is quite expensive for large premium lists because each premium list
|
||||
* entry is a separate Datastore entity, and loading them this way bypasses the in-memory caches.
|
||||
* Do not use this method if all you need to do is check the price of a small number of labels!
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static Map<String, PremiumListEntry> loadPremiumListEntries(PremiumList premiumList) {
|
||||
try {
|
||||
ImmutableMap.Builder<String, PremiumListEntry> entriesMap = new ImmutableMap.Builder<>();
|
||||
if (premiumList.getRevisionKey() != null) {
|
||||
for (PremiumListEntry entry : premiumList.queryEntriesForCurrentRevision()) {
|
||||
entriesMap.put(entry.getLabel(), entry);
|
||||
}
|
||||
}
|
||||
return entriesMap.build();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(
|
||||
"Could not retrieve entries for premium list " + premiumList.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private PremiumListUtils() {}
|
||||
}
|
|
@ -15,6 +15,8 @@
|
|||
package google.registry.tools;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.model.registry.label.PremiumListUtils.deletePremiumList;
|
||||
import static google.registry.model.registry.label.PremiumListUtils.doesPremiumListExist;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
|
@ -43,7 +45,7 @@ final class DeletePremiumListCommand extends ConfirmingCommand implements Remote
|
|||
@Override
|
||||
protected void init() throws Exception {
|
||||
checkArgument(
|
||||
PremiumList.exists(name),
|
||||
doesPremiumListExist(name),
|
||||
"Cannot delete the premium list %s because it doesn't exist.",
|
||||
name);
|
||||
premiumList = PremiumList.get(name).get();
|
||||
|
@ -61,7 +63,7 @@ final class DeletePremiumListCommand extends ConfirmingCommand implements Remote
|
|||
|
||||
@Override
|
||||
protected String execute() throws Exception {
|
||||
premiumList.delete();
|
||||
deletePremiumList(premiumList);
|
||||
return String.format("Deleted premium list '%s'.\n", premiumList.getName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ package google.registry.tools.server;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.model.registry.Registries.assertTldExists;
|
||||
import static google.registry.model.registry.label.PremiumList.saveWithEntries;
|
||||
import static google.registry.model.registry.label.PremiumListUtils.doesPremiumListExist;
|
||||
import static google.registry.model.registry.label.PremiumListUtils.savePremiumListAndEntries;
|
||||
import static google.registry.request.Action.Method.POST;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
|
@ -43,8 +44,7 @@ public class CreatePremiumListAction extends CreateOrUpdatePremiumListAction {
|
|||
@Override
|
||||
protected void savePremiumList() {
|
||||
checkArgument(
|
||||
!PremiumList.exists(name),
|
||||
"A premium list of this name already exists: %s.", name);
|
||||
!doesPremiumListExist(name), "A premium list of this name already exists: %s.", name);
|
||||
if (!override) {
|
||||
assertTldExists(name);
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ public class CreatePremiumListAction extends CreateOrUpdatePremiumListAction {
|
|||
List<String> inputDataPreProcessed =
|
||||
Splitter.on('\n').omitEmptyStrings().splitToList(inputData);
|
||||
PremiumList premiumList = new PremiumList.Builder().setName(name).build();
|
||||
saveWithEntries(premiumList, inputDataPreProcessed);
|
||||
savePremiumListAndEntries(premiumList, inputDataPreProcessed);
|
||||
|
||||
String message =
|
||||
String.format(
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
package google.registry.tools.server;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.model.registry.label.PremiumList.saveWithEntries;
|
||||
import static google.registry.model.registry.label.PremiumListUtils.savePremiumListAndEntries;
|
||||
import static google.registry.request.Action.Method.POST;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
@ -49,7 +49,8 @@ public class UpdatePremiumListAction extends CreateOrUpdatePremiumListAction {
|
|||
logger.infofmt("Got the following input data: %s", inputData);
|
||||
List<String> inputDataPreProcessed =
|
||||
Splitter.on('\n').omitEmptyStrings().splitToList(inputData);
|
||||
PremiumList newPremiumList = saveWithEntries(existingPremiumList.get(), inputDataPreProcessed);
|
||||
PremiumList newPremiumList =
|
||||
savePremiumListAndEntries(existingPremiumList.get(), inputDataPreProcessed);
|
||||
|
||||
String message =
|
||||
String.format(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue