From 047bbf186e5f960706704e000b743579a5e6d1f8 Mon Sep 17 00:00:00 2001 From: mcilwain Date: Mon, 9 May 2016 10:30:13 -0700 Subject: [PATCH] Extract premium pricing to a PricingEngine interface This refactors the existing premium list functionality into the new class StaticPremiumListPricingEngine, which implements PricingEngine. A backfill @OnLoad is provided to default existing Registry entities into the static implementation. For now there is just this one implementation. Dagger map multibinding is used to generate the total set of allowed pricing engines, and allows other parties to plug in their own implementations. The pricing engine is a required field on the Registry object. If you don't want a particular Registry to actually have a premium list, then use the static pricing engine but don't actually set a premium list. A subsequent CL will refactor the Key field on the Registry entity class to be handled solely by the StaticPremiumListPricingEngine implementation. Going forward, all configuration and implementation details that are specific to a given pricing engine should be handled by that pricing engine, and not as fields on the Registry object. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=121850176 --- java/google/registry/flows/BUILD | 1 + .../flows/domain/BaseDomainCreateFlow.java | 6 +- .../flows/domain/DomainAllocateFlow.java | 19 +- .../flows/domain/DomainCheckFlow.java | 3 +- .../flows/domain/DomainDeleteFlow.java | 4 +- .../flows/domain/DomainFlowUtils.java | 21 +- .../flows/domain/DomainRenewFlow.java | 4 +- .../domain/DomainRestoreRequestFlow.java | 5 +- .../domain/DomainTransferApproveFlow.java | 5 +- .../domain/DomainTransferRequestFlow.java | 7 +- .../registry/model/pricing/PricingEngine.java | 31 +++ .../StaticPremiumListPricingEngine.java | 53 +++++ .../registry/model/registry/Registry.java | 90 +++++---- .../monitoring/whitebox/WhiteboxModule.java | 6 +- java/google/registry/pricing/BUILD | 28 +++ .../registry/pricing/PricingComponent.java | 36 ++++ .../registry/pricing/PricingEngineProxy.java | 107 ++++++++++ .../registry/pricing/PricingModule.java | 47 +++++ java/google/registry/repositories.bzl | 12 +- java/google/registry/tools/BUILD | 1 + .../tools/CreateAnchorTenantCommand.java | 8 +- .../tools/CreateOrUpdateTldCommand.java | 10 +- .../tools/CreatePremiumListCommand.java | 3 - javatests/google/registry/flows/BUILD | 1 + .../flows/domain/DomainCreateFlowTest.java | 8 +- .../registry/model/RoidSuffixesTest.java | 4 +- .../registry/model/registry/RegistryTest.java | 110 ++--------- .../model/registry/label/PremiumListTest.java | 7 +- javatests/google/registry/pricing/BUILD | 34 ++++ .../pricing/PricingEngineProxyTest.java | 182 ++++++++++++++++++ javatests/google/registry/testing/BUILD | 1 + .../registry/testing/DatastoreHelper.java | 5 +- 32 files changed, 659 insertions(+), 200 deletions(-) create mode 100644 java/google/registry/model/pricing/PricingEngine.java create mode 100644 java/google/registry/model/pricing/StaticPremiumListPricingEngine.java create mode 100644 java/google/registry/pricing/BUILD create mode 100644 java/google/registry/pricing/PricingComponent.java create mode 100644 java/google/registry/pricing/PricingEngineProxy.java create mode 100644 java/google/registry/pricing/PricingModule.java create mode 100644 javatests/google/registry/pricing/BUILD create mode 100644 javatests/google/registry/pricing/PricingEngineProxyTest.java diff --git a/java/google/registry/flows/BUILD b/java/google/registry/flows/BUILD index 2ded8635f..8eaa33348 100644 --- a/java/google/registry/flows/BUILD +++ b/java/google/registry/flows/BUILD @@ -40,6 +40,7 @@ java_library( "//java/google/registry/mapreduce/inputs", "//java/google/registry/model", "//java/google/registry/monitoring/whitebox", + "//java/google/registry/pricing", "//java/google/registry/request", "//java/google/registry/security:servlets", "//java/google/registry/tldconfig/idn", diff --git a/java/google/registry/flows/domain/BaseDomainCreateFlow.java b/java/google/registry/flows/domain/BaseDomainCreateFlow.java index 57a87f2d4..dc5535cb8 100644 --- a/java/google/registry/flows/domain/BaseDomainCreateFlow.java +++ b/java/google/registry/flows/domain/BaseDomainCreateFlow.java @@ -35,6 +35,7 @@ import static google.registry.model.EppResourceUtils.loadByUniqueId; import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.model.registry.Registries.findTldForName; import static google.registry.model.registry.label.ReservedList.matchesAnchorTenantReservation; +import static google.registry.pricing.PricingEngineProxy.getDomainCreateCost; import com.google.common.base.Optional; import com.google.common.net.InternetDomainName; @@ -176,8 +177,7 @@ public abstract class BaseDomainCreateFlow getPremiumPrice( + String secondLevelDomainName, DateTime priceTime, String clientIdentifier); +} diff --git a/java/google/registry/model/pricing/StaticPremiumListPricingEngine.java b/java/google/registry/model/pricing/StaticPremiumListPricingEngine.java new file mode 100644 index 000000000..8a114594e --- /dev/null +++ b/java/google/registry/model/pricing/StaticPremiumListPricingEngine.java @@ -0,0 +1,53 @@ +// Copyright 2016 The Domain Registry 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.pricing; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static google.registry.util.DomainNameUtils.getTldFromSld; + +import com.google.common.base.Optional; +import com.google.common.net.InternetDomainName; + +import google.registry.model.registry.Registry; +import google.registry.model.registry.label.PremiumList; + +import org.joda.money.Money; +import org.joda.time.DateTime; + +import javax.inject.Inject; + +/** A premium list pricing engine that stores static pricing information in Datastore entities. */ +public final class StaticPremiumListPricingEngine implements PricingEngine { + + @Inject StaticPremiumListPricingEngine() {} + + @Override + public Optional getPremiumPrice( + String secondLevelDomainName, DateTime priceTime, String clientIdentifier) { + // Note that clientIdentifier and priceTime are not used for determining premium pricing for + // static premium lists. + String tld = getTldFromSld(secondLevelDomainName); + Registry registry = Registry.get(checkNotNull(tld, "tld")); + if (registry.getPremiumList() == null) { + return Optional.absent(); + } + String listName = registry.getPremiumList().getName(); + Optional premiumList = PremiumList.get(listName); + checkState(premiumList.isPresent(), "Could not load premium list: %s", listName); + String label = InternetDomainName.from(secondLevelDomainName).parts().get(0); + return premiumList.get().getPremiumPrice(label); + } +} diff --git a/java/google/registry/model/registry/Registry.java b/java/google/registry/model/registry/Registry.java index acc662235..fb836a7d0 100644 --- a/java/google/registry/model/registry/Registry.java +++ b/java/google/registry/model/registry/Registry.java @@ -21,7 +21,6 @@ import static com.google.common.base.Predicates.not; import static google.registry.model.common.EntityGroupRoot.getCrossTldKey; import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.model.ofy.Ofy.RECOMMENDED_MEMCACHE_EXPIRATION; -import static google.registry.model.registry.label.PremiumList.getPremiumPrice; import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy; import static google.registry.util.DateTimeUtils.END_OF_TIME; import static google.registry.util.PreconditionsUtils.checkArgumentNotNull; @@ -47,6 +46,7 @@ import com.googlecode.objectify.annotation.Embed; import com.googlecode.objectify.annotation.Entity; import com.googlecode.objectify.annotation.Id; import com.googlecode.objectify.annotation.Mapify; +import com.googlecode.objectify.annotation.OnLoad; import com.googlecode.objectify.annotation.OnSave; import com.googlecode.objectify.annotation.Parent; @@ -57,6 +57,8 @@ import google.registry.model.ImmutableObject; import google.registry.model.common.EntityGroupRoot; import google.registry.model.common.TimedTransitionProperty; import google.registry.model.common.TimedTransitionProperty.TimedTransition; +import google.registry.model.pricing.PricingEngine; +import google.registry.model.pricing.StaticPremiumListPricingEngine; import google.registry.model.registry.label.PremiumList; import google.registry.model.registry.label.ReservedList; import google.registry.util.Idn; @@ -238,6 +240,27 @@ public class Registry extends ImmutableObject implements Buildable { CACHE.invalidate(tldStr); } + /** + * Backfill the Registry entities that were saved before this field was added. + * + *

Note that this defaults to the {@link StaticPremiumListPricingEngine}. + */ + // TODO(b/26901539): Remove this backfill once it is populated on all Registry entities. + @OnLoad + void backfillPricingEngine() { + if (pricingEngineClassName == null) { + pricingEngineClassName = StaticPremiumListPricingEngine.class.getCanonicalName(); + } + } + + /** + * The fully qualified canonical classname of the pricing engine that this TLD uses. + * + *

This must be a valid key for the map of pricing engines injected by + * @Inject Map + */ + String pricingEngineClassName; + /** * The unicode-aware representation of the TLD associated with this {@link Registry}. *

@@ -271,7 +294,7 @@ public class Registry extends ImmutableObject implements Buildable { return nullToEmptyImmutableCopy(reservedLists); } - /** The {@link PremiumList} for this TLD. */ + /** The static {@link PremiumList} for this TLD, if there is one. */ Key premiumList; /** Should RDE upload a nightly escrow deposit for this TLD? */ @@ -442,7 +465,10 @@ public class Registry extends ImmutableObject implements Buildable { return currency; } - /** Use {@link #getDomainCreateCost} instead of this to find the cost for a domain create. */ + /** + * Use PricingUtils.getDomainCreateCost instead of this to find the cost for a + * domain create. + */ @VisibleForTesting public Money getStandardCreateCost() { return createBillingCost; @@ -457,8 +483,9 @@ public class Registry extends ImmutableObject implements Buildable { } /** - * Use {@link #getDomainRenewCost} instead of this to find the cost for a domain renew, and all - * derived costs (i.e. autorenews, transfers, and the per-domain part of a restore cost). + * Use PricingUtils.getDomainRenewCost instead of this to find the cost for a domain + * renewal, and all derived costs (i.e. autorenews, transfers, and the per-domain part of a + * restore cost). */ @VisibleForTesting public Money getStandardRenewCost(DateTime now) { @@ -480,47 +507,6 @@ public class Registry extends ImmutableObject implements Buildable { return renewBillingCostTransitions.toValueMap(); } - private Optional getPremiumPriceForSld(String sldName) { - return getPremiumPriceForSld(InternetDomainName.from(sldName)); - } - - private Optional getPremiumPriceForSld(InternetDomainName domainName) { - checkArgument(getTld().equals(domainName.parent()), - "Domain name %s is not an SLD for TLD %s", domainName.toString(), tldStr); - String label = domainName.parts().get(0); - return getPremiumPrice(label, tldStr); - } - - /** Returns true if the given domain name is on the premium price list. */ - public boolean isPremiumName(String domainName, DateTime priceTime, String clientIdentifier) { - return isPremiumName(InternetDomainName.from(domainName), priceTime, clientIdentifier); - } - - /** Returns true if the given domain name is on the premium price list. */ - @SuppressWarnings("unused") - public boolean isPremiumName( - InternetDomainName domainName, DateTime priceTime, String clientIdentifier) { - return getPremiumPriceForSld(domainName).isPresent(); - } - - /** Returns the billing cost for registering the specified domain name for this many years. */ - @SuppressWarnings("unused") - public Money getDomainCreateCost( - String domainName, DateTime priceTime, String clientIdentifier, int years) { - checkArgument(years > 0, "Number of years must be positive"); - Money annualCost = getPremiumPriceForSld(domainName).or(getStandardCreateCost()); - return annualCost.multipliedBy(years); - } - - /** Returns the billing cost for renewing the specified domain name for this many years. */ - @SuppressWarnings("unused") - public Money getDomainRenewCost( - String domainName, DateTime priceTime, String clientIdentifier, int years) { - checkArgument(years > 0, "Number of years must be positive"); - Money annualCost = getPremiumPriceForSld(domainName).or(getStandardRenewCost(priceTime)); - return annualCost.multipliedBy(years); - } - public String getLordnUsername() { return lordnUsername; } @@ -529,6 +515,10 @@ public class Registry extends ImmutableObject implements Buildable { return claimsPeriodEnd; } + public String getPricingEngineClassName() { + return pricingEngineClassName; + } + public ImmutableSet getAllowedRegistrantContactIds() { return nullToEmptyImmutableCopy(allowedRegistrantContactIds); } @@ -595,6 +585,12 @@ public class Registry extends ImmutableObject implements Buildable { return this; } + public Builder setPricingEngineClass(Class pricingEngineClass) { + getInstance().pricingEngineClassName = + checkArgumentNotNull(pricingEngineClass).getCanonicalName(); + return this; + } + public Builder setAddGracePeriodLength(Duration addGracePeriodLength) { checkArgument(addGracePeriodLength.isLongerThan(Duration.ZERO), "addGracePeriodLength must be non-zero"); @@ -800,6 +796,8 @@ public class Registry extends ImmutableObject implements Buildable { return money.getCurrencyUnit().equals(instance.currency); }}), "Renew cost must be in the registry's currency"); + checkArgumentNotNull( + instance.pricingEngineClassName, "All registries must have a configured pricing engine"); instance.tldStrId = tldName; instance.tldUnicode = Idn.toUnicode(tldName); return super.build(); diff --git a/java/google/registry/monitoring/whitebox/WhiteboxModule.java b/java/google/registry/monitoring/whitebox/WhiteboxModule.java index c3596ca39..b98684c53 100644 --- a/java/google/registry/monitoring/whitebox/WhiteboxModule.java +++ b/java/google/registry/monitoring/whitebox/WhiteboxModule.java @@ -14,7 +14,6 @@ package google.registry.monitoring.whitebox; -import static dagger.Provides.Type.MAP; import static google.registry.monitoring.whitebox.EntityIntegrityAlertsSchema.ENTITY_INTEGRITY_ALERTS_SCHEMA_FIELDS; import static google.registry.monitoring.whitebox.EntityIntegrityAlertsSchema.TABLE_ID; import static google.registry.monitoring.whitebox.EppMetrics.EPPMETRICS_SCHEMA_FIELDS; @@ -27,6 +26,7 @@ import com.google.common.collect.ImmutableList; import dagger.Module; import dagger.Provides; +import dagger.multibindings.IntoMap; import dagger.multibindings.StringKey; import google.registry.request.Parameter; @@ -41,13 +41,13 @@ import javax.servlet.http.HttpServletRequest; @Module public class WhiteboxModule { - @Provides(type = MAP) + @Provides @IntoMap @StringKey(EPPMETRICS_TABLE_ID) static ImmutableList provideEppMetricsSchema() { return EPPMETRICS_SCHEMA_FIELDS; } - @Provides(type = MAP) + @Provides @IntoMap @StringKey(TABLE_ID) static ImmutableList provideEntityIntegrityAlertsSchema() { return ENTITY_INTEGRITY_ALERTS_SCHEMA_FIELDS; diff --git a/java/google/registry/pricing/BUILD b/java/google/registry/pricing/BUILD new file mode 100644 index 000000000..d11a79a06 --- /dev/null +++ b/java/google/registry/pricing/BUILD @@ -0,0 +1,28 @@ +package( + default_visibility = ["//java/google/registry:registry_project"], +) + +licenses(["notice"]) # Apache 2.0 + + +java_library( + name = "pricing", + srcs = glob(["*.java"]), + deps = [ + "//java/com/google/common/annotations", + "//java/com/google/common/base", + "//java/com/google/common/collect", + "//java/com/google/common/io", + "//java/com/google/common/net", + "//java/com/google/common/util/concurrent", + "//third_party/java/dagger", + "//third_party/java/joda_money", + "//third_party/java/joda_time", + "//third_party/java/jsr305_annotations", + "//third_party/java/jsr330_inject", + "//third_party/java/objectify:objectify-v4_1", + "//third_party/java/servlet/servlet_api", + "//java/google/registry/model", + "//java/google/registry/util", + ], +) diff --git a/java/google/registry/pricing/PricingComponent.java b/java/google/registry/pricing/PricingComponent.java new file mode 100644 index 000000000..c716d371d --- /dev/null +++ b/java/google/registry/pricing/PricingComponent.java @@ -0,0 +1,36 @@ +// Copyright 2016 The Domain Registry 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.pricing; + +import dagger.Component; + +import google.registry.model.pricing.PricingEngine; + +import java.util.Map; + +import javax.inject.Singleton; + +/** + * Dagger component with instance lifetime for pricing engines. + * + *

This component only exists because the flows themselves are not yet injected. Once they are, + * this separate component can be removed, and the pricingEngines() map added to the relevant + * component used to construct the flows. + */ +@Singleton +@Component(modules = {PricingModule.class}) +interface PricingComponent { + Map, PricingEngine> pricingEngines(); +} diff --git a/java/google/registry/pricing/PricingEngineProxy.java b/java/google/registry/pricing/PricingEngineProxy.java new file mode 100644 index 000000000..772e54de8 --- /dev/null +++ b/java/google/registry/pricing/PricingEngineProxy.java @@ -0,0 +1,107 @@ +// Copyright 2016 The Domain Registry 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.pricing; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; +import static google.registry.model.registry.Registries.assertTldExists; +import static google.registry.util.DomainNameUtils.getTldFromSld; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import com.google.common.net.InternetDomainName; + +import google.registry.model.pricing.PricingEngine; +import google.registry.model.registry.Registry; + +import org.joda.money.Money; +import org.joda.time.DateTime; + +import java.util.Map; + +/** + * A global proxy providing static methods for getting premium prices that dispatches requests + * correctly to the relevant {@link PricingEngine} implementation per TLD. + */ +public final class PricingEngineProxy { + + private static final Map, PricingEngine> pricingEngineClasses = + DaggerPricingComponent.create().pricingEngines(); + + // Dagger map keys have to be provided with constant values that are known at compile time, so it + // can't be done using clazz.getCanonicalName(). So we construct the map by canonical name here, + // at runtime. + private static final ImmutableMap pricingEngines = + Maps.uniqueIndex( + pricingEngineClasses.values(), + new Function() { + @Override + public String apply(PricingEngine pricingEngine) { + return pricingEngine.getClass().getCanonicalName(); + }}); + + /** Returns true if the given domain name is on the premium price list. */ + public static boolean isPremiumName( + String domainName, DateTime priceTime, String clientIdentifier) { + return isPremiumName(InternetDomainName.from(domainName), priceTime, clientIdentifier); + } + + /** Returns true if the given domain name is on the premium price list. */ + public static boolean isPremiumName( + InternetDomainName domainName, DateTime priceTime, String clientIdentifier) { + return getPremiumPriceForDomainName(domainName, priceTime, clientIdentifier).isPresent(); + } + + /** Returns the billing cost for registering the specified domain name for this many years. */ + public static Money getDomainCreateCost( + String domainName, DateTime priceTime, String clientIdentifier, int years) { + checkArgument(years > 0, "Number of years must be positive"); + Optional annualCost = + getPremiumPriceForDomainName( + InternetDomainName.from(domainName), priceTime, clientIdentifier); + return annualCost + .or(Registry.get(getTldFromSld(domainName)).getStandardCreateCost()) + .multipliedBy(years); + } + + /** Returns the billing cost for renewing the specified domain name for this many years. */ + public static Money getDomainRenewCost( + String domainName, DateTime priceTime, String clientIdentifier, int years) { + checkArgument(years > 0, "Number of years must be positive"); + Optional annualCost = + getPremiumPriceForDomainName( + InternetDomainName.from(domainName), priceTime, clientIdentifier); + return annualCost + .or(Registry.get(getTldFromSld(domainName)).getStandardRenewCost(priceTime)) + .multipliedBy(years); + } + + /** + * Returns whether the given domain name is premium by dispatching to the appropriate + * {@link PricingEngine} based on what is configured for the TLD that the domain is under. + */ + private static Optional getPremiumPriceForDomainName( + InternetDomainName domainName, DateTime priceTime, String clientIdentifier) { + String tld = assertTldExists(getTldFromSld(domainName)); + String clazz = Registry.get(tld).getPricingEngineClassName(); + PricingEngine engine = pricingEngines.get(clazz); + checkState(engine != null, "Could not load pricing engine %s for TLD %s", clazz, tld); + return engine.getPremiumPrice(domainName.toString(), priceTime, clientIdentifier); + } + + private PricingEngineProxy() {} +} diff --git a/java/google/registry/pricing/PricingModule.java b/java/google/registry/pricing/PricingModule.java new file mode 100644 index 000000000..ed6e07fad --- /dev/null +++ b/java/google/registry/pricing/PricingModule.java @@ -0,0 +1,47 @@ +// Copyright 2016 The Domain Registry 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.pricing; + +import dagger.MapKey; +import dagger.Module; +import dagger.Provides; +import dagger.multibindings.IntoMap; + +import google.registry.model.pricing.PricingEngine; +import google.registry.model.pricing.StaticPremiumListPricingEngine; + +/** + * Dagger module for injecting pricing engines. + * + *

To add a new pricing engine, create a new class that implements {@link PricingEngine}, and add + * a module that provides an instance of PricingEngine with a PricingEngineClassKey + * annotation with the class of the implementation and also @Provides @IntoMap + * annotations. + */ +@Module +public class PricingModule { + + /** The annotation used for PricingEngine implementation keys. */ + @MapKey + @interface PricingEngineClassKey { + Class value(); + } + + @Provides @IntoMap + @PricingEngineClassKey(StaticPremiumListPricingEngine.class) + static PricingEngine provideStaticPremiumList(StaticPremiumListPricingEngine engine) { + return engine; + } +} diff --git a/java/google/registry/repositories.bzl b/java/google/registry/repositories.bzl index 10430a78a..f456c61d6 100644 --- a/java/google/registry/repositories.bzl +++ b/java/google/registry/repositories.bzl @@ -190,20 +190,20 @@ def domain_registry_repositories(): native.maven_jar( name = "dagger", - artifact = "com.google.dagger:dagger:2.0.2", - sha1 = "de8416eda7b2fd7c25836b140c39e1cbf10542f6", + artifact = "com.google.dagger:dagger:2.4", + sha1 = "6b290a792253035c9fcc912d6a4d7efb3e850211", ) native.maven_jar( name = "dagger_compiler", - artifact = "com.google.dagger:dagger-compiler:2.0.2", - sha1 = "1170f75c1ce293f80755bbc9fcd60e0765022bd0", + artifact = "com.google.dagger:dagger-compiler:2.4", + sha1 = "01053c9ef441e93088c9261c33163f6af30766b7", ) native.maven_jar( name = "dagger_producers", - artifact = "com.google.dagger:dagger-producers:2.0-beta", - sha1 = "80276338d1c2542ebebac542b535d1ecd48a3fd7", + artifact = "com.google.dagger:dagger-producers:2.4", + sha1 = "f334a19afdc2ce2d8d5191f8a0fac2321bdd50fc", ) native.maven_jar( diff --git a/java/google/registry/tools/BUILD b/java/google/registry/tools/BUILD index e8a021582..fc874f97d 100644 --- a/java/google/registry/tools/BUILD +++ b/java/google/registry/tools/BUILD @@ -49,6 +49,7 @@ java_library( "//java/google/registry/flows", "//java/google/registry/keyring/api", "//java/google/registry/model", + "//java/google/registry/pricing", "//java/google/registry/rde", "//java/google/registry/security", "//java/google/registry/request:modules", diff --git a/java/google/registry/tools/CreateAnchorTenantCommand.java b/java/google/registry/tools/CreateAnchorTenantCommand.java index d4944e0b6..86a7271a8 100644 --- a/java/google/registry/tools/CreateAnchorTenantCommand.java +++ b/java/google/registry/tools/CreateAnchorTenantCommand.java @@ -17,6 +17,7 @@ package google.registry.tools; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Strings.isNullOrEmpty; import static google.registry.model.registry.Registries.findTldForNameOrThrow; +import static google.registry.pricing.PricingEngineProxy.getDomainCreateCost; import static org.joda.time.DateTimeZone.UTC; import com.google.common.net.InternetDomainName; @@ -25,7 +26,6 @@ import com.google.template.soy.data.SoyMapData; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; -import google.registry.model.registry.Registry; import google.registry.tools.Command.GtechCommand; import google.registry.tools.soy.CreateAnchorTenantSoyInfo; @@ -81,15 +81,15 @@ final class CreateAnchorTenantCommand extends MutatingEppToolCommand implements @Override protected void initMutatingEppToolCommand() { checkArgument(superuser, "This command must be run as a superuser."); - String tld = findTldForNameOrThrow(InternetDomainName.from(domainName)).toString(); + findTldForNameOrThrow(InternetDomainName.from(domainName)); // Check that the tld exists. if (isNullOrEmpty(password)) { password = passwordGenerator.createPassword(PASSWORD_LENGTH); } Money cost = null; if (fee) { - cost = Registry.get(tld) - .getDomainCreateCost( + cost = + getDomainCreateCost( domainName, DateTime.now(UTC), clientIdentifier, DEFAULT_ANCHOR_TENANT_PERIOD_YEARS); } diff --git a/java/google/registry/tools/CreateOrUpdateTldCommand.java b/java/google/registry/tools/CreateOrUpdateTldCommand.java index 8a48469bb..22a73d4ea 100644 --- a/java/google/registry/tools/CreateOrUpdateTldCommand.java +++ b/java/google/registry/tools/CreateOrUpdateTldCommand.java @@ -35,6 +35,7 @@ import com.google.common.collect.ImmutableSortedMap; import com.beust.jcommander.Parameter; import com.googlecode.objectify.Key; +import google.registry.model.pricing.StaticPremiumListPricingEngine; import google.registry.model.registry.Registries; import google.registry.model.registry.Registry; import google.registry.model.registry.Registry.TldState; @@ -259,8 +260,13 @@ abstract class CreateOrUpdateTldCommand extends MutatingCommand { "The roid suffix %s is already in use", roidSuffix); } - Registry.Builder builder = oldRegistry == null - ? new Registry.Builder().setTldStr(tld) : oldRegistry.asBuilder(); + // TODO(b/26901539): Add a flag to set the pricing engine once we have more than one option. + Registry.Builder builder = + oldRegistry == null + ? new Registry.Builder() + .setTldStr(tld) + .setPricingEngineClass(StaticPremiumListPricingEngine.class) + : oldRegistry.asBuilder(); if (escrow != null) { builder.setEscrowEnabled(escrow); diff --git a/java/google/registry/tools/CreatePremiumListCommand.java b/java/google/registry/tools/CreatePremiumListCommand.java index df3ee97f1..fbbdecd92 100644 --- a/java/google/registry/tools/CreatePremiumListCommand.java +++ b/java/google/registry/tools/CreatePremiumListCommand.java @@ -22,13 +22,10 @@ import com.beust.jcommander.Parameters; import google.registry.model.registry.label.PremiumList; import google.registry.tools.server.CreatePremiumListAction; -import javax.annotation.Nullable; - /** Command to create a {@link PremiumList} on Datastore. */ @Parameters(separators = " =", commandDescription = "Create a PremiumList in Datastore.") public class CreatePremiumListCommand extends CreateOrUpdatePremiumListCommand { - @Nullable @Parameter( names = {"-o", "--override"}, description = "Override restrictions on premium list naming") diff --git a/javatests/google/registry/flows/BUILD b/javatests/google/registry/flows/BUILD index ab253abe8..5040d2925 100644 --- a/javatests/google/registry/flows/BUILD +++ b/javatests/google/registry/flows/BUILD @@ -46,6 +46,7 @@ java_library( "//java/google/registry/mapreduce", "//java/google/registry/model", "//java/google/registry/monitoring/whitebox", + "//java/google/registry/pricing", "//java/google/registry/request", "//java/google/registry/security", "//java/google/registry/security:servlets", diff --git a/javatests/google/registry/flows/domain/DomainCreateFlowTest.java b/javatests/google/registry/flows/domain/DomainCreateFlowTest.java index 3abb55d67..3ecf36317 100644 --- a/javatests/google/registry/flows/domain/DomainCreateFlowTest.java +++ b/javatests/google/registry/flows/domain/DomainCreateFlowTest.java @@ -16,6 +16,7 @@ package google.registry.flows.domain; import static com.google.common.io.BaseEncoding.base16; import static com.google.common.truth.Truth.assertThat; +import static google.registry.pricing.PricingEngineProxy.isPremiumName; import static google.registry.testing.DatastoreHelper.assertBillingEvents; import static google.registry.testing.DatastoreHelper.createTld; import static google.registry.testing.DatastoreHelper.deleteTld; @@ -179,10 +180,9 @@ public class DomainCreateFlowTest extends ResourceFlowTestCase