mirror of
https://github.com/google/nomulus.git
synced 2025-05-13 16:07:15 +02:00
Add a custom logic framework to provide pluggable extensibility
To add additional logic for flow code, write custom classes that extend the existing custom logic classes (of which DomainCreateFlowCustomLogic is the first provided example), along with a class that extends CustomLogicFactory to provide instances of the new custom logic classes. Then configure the fully qualified class name of your new custom logic factory in ConfigModule.provideCustomLogicFactoryClass(). ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=139221577
This commit is contained in:
parent
3942f0768b
commit
4d2e0941f3
15 changed files with 435 additions and 17 deletions
|
@ -914,4 +914,11 @@ public final class ConfigModule {
|
||||||
public static String provideGreetingServerId() {
|
public static String provideGreetingServerId() {
|
||||||
return "Charleston Road Registry";
|
return "Charleston Road Registry";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Config("customLogicFactoryClass")
|
||||||
|
public static String provideCustomLogicFactoryClass() {
|
||||||
|
// TODO(b/32875427): This will be moved into configuration in a text file in a future refactor.
|
||||||
|
return "google.registry.flows.custom.CustomLogicFactory";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import google.registry.flows.contact.ContactTransferQueryFlow;
|
||||||
import google.registry.flows.contact.ContactTransferRejectFlow;
|
import google.registry.flows.contact.ContactTransferRejectFlow;
|
||||||
import google.registry.flows.contact.ContactTransferRequestFlow;
|
import google.registry.flows.contact.ContactTransferRequestFlow;
|
||||||
import google.registry.flows.contact.ContactUpdateFlow;
|
import google.registry.flows.contact.ContactUpdateFlow;
|
||||||
|
import google.registry.flows.custom.CustomLogicModule;
|
||||||
import google.registry.flows.domain.ClaimsCheckFlow;
|
import google.registry.flows.domain.ClaimsCheckFlow;
|
||||||
import google.registry.flows.domain.DomainAllocateFlow;
|
import google.registry.flows.domain.DomainAllocateFlow;
|
||||||
import google.registry.flows.domain.DomainApplicationCreateFlow;
|
import google.registry.flows.domain.DomainApplicationCreateFlow;
|
||||||
|
@ -66,6 +67,7 @@ import google.registry.util.SystemSleeper.SystemSleeperModule;
|
||||||
@Subcomponent(modules = {
|
@Subcomponent(modules = {
|
||||||
AsyncFlowsModule.class,
|
AsyncFlowsModule.class,
|
||||||
ConfigModule.class,
|
ConfigModule.class,
|
||||||
|
CustomLogicModule.class,
|
||||||
DnsModule.class,
|
DnsModule.class,
|
||||||
FlowModule.class,
|
FlowModule.class,
|
||||||
FlowComponent.FlowComponentModule.class,
|
FlowComponent.FlowComponentModule.class,
|
||||||
|
|
|
@ -14,7 +14,10 @@
|
||||||
|
|
||||||
package google.registry.flows;
|
package google.registry.flows;
|
||||||
|
|
||||||
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||||
|
|
||||||
import google.registry.flows.EppException.CommandUseErrorException;
|
import google.registry.flows.EppException.CommandUseErrorException;
|
||||||
|
import google.registry.flows.custom.EntityChanges;
|
||||||
|
|
||||||
/** Static utility functions for flows. */
|
/** Static utility functions for flows. */
|
||||||
public final class FlowUtils {
|
public final class FlowUtils {
|
||||||
|
@ -28,6 +31,12 @@ public final class FlowUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Persists the saves and deletes in an {@link EntityChanges} to Datastore. */
|
||||||
|
public static void persistEntityChanges(EntityChanges entityChanges) {
|
||||||
|
ofy().save().entities(entityChanges.getSaves());
|
||||||
|
ofy().delete().keys(entityChanges.getDeletes());
|
||||||
|
}
|
||||||
|
|
||||||
/** Registrar is not logged in. */
|
/** Registrar is not logged in. */
|
||||||
public static class NotLoggedInException extends CommandUseErrorException {
|
public static class NotLoggedInException extends CommandUseErrorException {
|
||||||
public NotLoggedInException() {
|
public NotLoggedInException() {
|
||||||
|
|
41
java/google/registry/flows/custom/BaseFlowCustomLogic.java
Normal file
41
java/google/registry/flows/custom/BaseFlowCustomLogic.java
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
// Copyright 2016 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.flows.custom;
|
||||||
|
|
||||||
|
import google.registry.flows.SessionMetadata;
|
||||||
|
import google.registry.model.eppinput.EppInput;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abstract base class for all flow custom logic that stores the flow's {@link EppInput} and
|
||||||
|
* {@link SessionMetadata} for convenience. Both of these are immutable.
|
||||||
|
*/
|
||||||
|
public abstract class BaseFlowCustomLogic {
|
||||||
|
|
||||||
|
private final EppInput eppInput;
|
||||||
|
private final SessionMetadata sessionMetadata;
|
||||||
|
|
||||||
|
protected BaseFlowCustomLogic(EppInput eppInput, SessionMetadata sessionMetadata) {
|
||||||
|
this.eppInput = eppInput;
|
||||||
|
this.sessionMetadata = sessionMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected EppInput getEppInput() {
|
||||||
|
return eppInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SessionMetadata getSessionMetadata() {
|
||||||
|
return sessionMetadata;
|
||||||
|
}
|
||||||
|
}
|
38
java/google/registry/flows/custom/CustomLogicFactory.java
Normal file
38
java/google/registry/flows/custom/CustomLogicFactory.java
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright 2016 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.flows.custom;
|
||||||
|
|
||||||
|
import google.registry.config.ConfigModule;
|
||||||
|
import google.registry.flows.SessionMetadata;
|
||||||
|
import google.registry.model.eppinput.EppInput;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A no-op base custom logic factory.
|
||||||
|
*
|
||||||
|
* <p>To add custom logic, extend this class, then configure it in
|
||||||
|
* {@link ConfigModule#provideCustomLogicFactoryClass}. The eppInput and sessionMetadata parameters
|
||||||
|
* are unused in the base implementation, but are provided so that custom implementations can
|
||||||
|
* optionally determine how to construct/choose which custom logic class to return. A common use
|
||||||
|
* case might be parsing TLD for domain-specific flows from the EppInput and then using that to
|
||||||
|
* choose a different custom logic implementation, or switching based on the registrar
|
||||||
|
* {@code clientId} in sessionMetadata.
|
||||||
|
*/
|
||||||
|
public class CustomLogicFactory {
|
||||||
|
|
||||||
|
public DomainCreateFlowCustomLogic forDomainCreateFlow(
|
||||||
|
EppInput eppInput, SessionMetadata sessionMetadata) {
|
||||||
|
return new DomainCreateFlowCustomLogic(eppInput, sessionMetadata);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright 2016 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.flows.custom;
|
||||||
|
|
||||||
|
import static google.registry.util.TypeUtils.getClassFromString;
|
||||||
|
import static google.registry.util.TypeUtils.instantiate;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
import google.registry.config.ConfigModule.Config;
|
||||||
|
|
||||||
|
/** Dagger module for custom logic factories. */
|
||||||
|
@Module
|
||||||
|
public class CustomLogicFactoryModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
static CustomLogicFactory provideCustomLogicFactory(
|
||||||
|
@Config("customLogicFactoryClass") String factoryClass) {
|
||||||
|
return instantiate(getClassFromString(factoryClass, CustomLogicFactory.class));
|
||||||
|
}
|
||||||
|
}
|
31
java/google/registry/flows/custom/CustomLogicModule.java
Normal file
31
java/google/registry/flows/custom/CustomLogicModule.java
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright 2016 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.flows.custom;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
import google.registry.flows.SessionMetadata;
|
||||||
|
import google.registry.model.eppinput.EppInput;
|
||||||
|
|
||||||
|
/** Dagger module to provide instances of custom logic classes for EPP flows. */
|
||||||
|
@Module
|
||||||
|
public class CustomLogicModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
static DomainCreateFlowCustomLogic provideDomainCreateFlowCustomLogic(
|
||||||
|
CustomLogicFactory factory, EppInput eppInput, SessionMetadata sessionMetadata) {
|
||||||
|
return factory.forDomainCreateFlow(eppInput, sessionMetadata);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
// Copyright 2016 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.flows.custom;
|
||||||
|
|
||||||
|
import com.google.auto.value.AutoValue;
|
||||||
|
import com.google.common.net.InternetDomainName;
|
||||||
|
import google.registry.flows.EppException;
|
||||||
|
import google.registry.flows.SessionMetadata;
|
||||||
|
import google.registry.model.ImmutableObject;
|
||||||
|
import google.registry.model.domain.DomainResource;
|
||||||
|
import google.registry.model.eppinput.EppInput;
|
||||||
|
import google.registry.model.reporting.HistoryEntry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A no-op base class for domain create flow custom logic.
|
||||||
|
*
|
||||||
|
* <p>Extend this class and override the hooks to perform custom logic.
|
||||||
|
*/
|
||||||
|
public class DomainCreateFlowCustomLogic extends BaseFlowCustomLogic {
|
||||||
|
|
||||||
|
protected DomainCreateFlowCustomLogic(EppInput eppInput, SessionMetadata sessionMetadata) {
|
||||||
|
super(eppInput, sessionMetadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A hook that runs at the end of the validation step to perform additional validation. */
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public void afterValidation(AfterValidationParameters parameters) throws EppException {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A hook that runs before new entities are persisted.
|
||||||
|
*
|
||||||
|
* <p>This takes the new entities as input and returns the actual entities to save. It is
|
||||||
|
* important to be careful when changing the flow behavior for existing entities, because the core
|
||||||
|
* logic across many different flows expects the existence of these entities and many of the
|
||||||
|
* fields on them.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public EntityChanges beforeSave(BeforeSaveParameters parameters, EntityChanges entityChanges)
|
||||||
|
throws EppException {
|
||||||
|
return entityChanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A class to encapsulate parameters for a call to {@link #afterValidation}. */
|
||||||
|
@AutoValue
|
||||||
|
public abstract static class AfterValidationParameters extends ImmutableObject {
|
||||||
|
|
||||||
|
public abstract InternetDomainName domainName();
|
||||||
|
public abstract int years();
|
||||||
|
|
||||||
|
public static Builder newBuilder() {
|
||||||
|
return new AutoValue_DomainCreateFlowCustomLogic_AfterValidationParameters.Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Builder for {@link AfterValidationParameters}. */
|
||||||
|
@AutoValue.Builder
|
||||||
|
public abstract static class Builder {
|
||||||
|
public abstract Builder setDomainName(InternetDomainName domainName);
|
||||||
|
public abstract Builder setYears(int years);
|
||||||
|
public abstract AfterValidationParameters build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A class to encapsulate parameters for a call to {@link #beforeSave}. */
|
||||||
|
@AutoValue
|
||||||
|
public abstract static class BeforeSaveParameters extends ImmutableObject {
|
||||||
|
|
||||||
|
public abstract DomainResource newDomain();
|
||||||
|
public abstract HistoryEntry historyEntry();
|
||||||
|
public abstract int years();
|
||||||
|
|
||||||
|
public static Builder newBuilder() {
|
||||||
|
return new AutoValue_DomainCreateFlowCustomLogic_BeforeSaveParameters.Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Builder for {@link BeforeSaveParameters}. */
|
||||||
|
@AutoValue.Builder
|
||||||
|
public abstract static class Builder {
|
||||||
|
public abstract Builder setNewDomain(DomainResource newDomain);
|
||||||
|
public abstract Builder setHistoryEntry(HistoryEntry historyEntry);
|
||||||
|
public abstract Builder setYears(int years);
|
||||||
|
public abstract BeforeSaveParameters build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
62
java/google/registry/flows/custom/EntityChanges.java
Normal file
62
java/google/registry/flows/custom/EntityChanges.java
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
// Copyright 2016 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.flows.custom;
|
||||||
|
|
||||||
|
import com.google.auto.value.AutoValue;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.googlecode.objectify.Key;
|
||||||
|
import google.registry.model.ImmutableObject;
|
||||||
|
|
||||||
|
/** A wrapper class that encapsulates Datastore entities to both save and delete. */
|
||||||
|
@AutoValue
|
||||||
|
public abstract class EntityChanges {
|
||||||
|
|
||||||
|
public abstract ImmutableSet<ImmutableObject> getSaves();
|
||||||
|
|
||||||
|
public abstract ImmutableSet<Key<ImmutableObject>> getDeletes();
|
||||||
|
|
||||||
|
public static Builder newBuilder() {
|
||||||
|
// Default both entities to save and entities to delete to empty sets, so that the build()
|
||||||
|
// method won't subsequently throw an exception if one doesn't end up being applicable.
|
||||||
|
return new AutoValue_EntityChanges.Builder()
|
||||||
|
.setSaves(ImmutableSet.<ImmutableObject>of())
|
||||||
|
.setDeletes(ImmutableSet.<Key<ImmutableObject>>of());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Builder for {@link EntityChanges}. */
|
||||||
|
@AutoValue.Builder
|
||||||
|
public abstract static class Builder {
|
||||||
|
|
||||||
|
public abstract Builder setSaves(ImmutableSet<ImmutableObject> entitiesToSave);
|
||||||
|
|
||||||
|
public abstract ImmutableSet.Builder<ImmutableObject> savesBuilder();
|
||||||
|
|
||||||
|
public Builder addSave(ImmutableObject entityToSave) {
|
||||||
|
savesBuilder().add(entityToSave);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Builder setDeletes(ImmutableSet<Key<ImmutableObject>> entitiesToDelete);
|
||||||
|
|
||||||
|
public abstract ImmutableSet.Builder<Key<ImmutableObject>> deletesBuilder();
|
||||||
|
|
||||||
|
public Builder addDelete(Key<ImmutableObject> entityToDelete) {
|
||||||
|
deletesBuilder().add(entityToDelete);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract EntityChanges build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
package google.registry.flows.domain;
|
package google.registry.flows.domain;
|
||||||
|
|
||||||
|
import static google.registry.flows.FlowUtils.persistEntityChanges;
|
||||||
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
|
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
|
||||||
import static google.registry.flows.ResourceFlowUtils.verifyResourceDoesNotExist;
|
import static google.registry.flows.ResourceFlowUtils.verifyResourceDoesNotExist;
|
||||||
import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld;
|
import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld;
|
||||||
|
@ -57,6 +58,8 @@ import google.registry.flows.FlowModule.ClientId;
|
||||||
import google.registry.flows.FlowModule.Superuser;
|
import google.registry.flows.FlowModule.Superuser;
|
||||||
import google.registry.flows.FlowModule.TargetId;
|
import google.registry.flows.FlowModule.TargetId;
|
||||||
import google.registry.flows.TransactionalFlow;
|
import google.registry.flows.TransactionalFlow;
|
||||||
|
import google.registry.flows.custom.DomainCreateFlowCustomLogic;
|
||||||
|
import google.registry.flows.custom.EntityChanges;
|
||||||
import google.registry.flows.domain.TldSpecificLogicProxy.EppCommandOperations;
|
import google.registry.flows.domain.TldSpecificLogicProxy.EppCommandOperations;
|
||||||
import google.registry.model.ImmutableObject;
|
import google.registry.model.ImmutableObject;
|
||||||
import google.registry.model.billing.BillingEvent;
|
import google.registry.model.billing.BillingEvent;
|
||||||
|
@ -162,6 +165,7 @@ public class DomainCreateFlow implements TransactionalFlow {
|
||||||
@Inject @Superuser boolean isSuperuser;
|
@Inject @Superuser boolean isSuperuser;
|
||||||
@Inject HistoryEntry.Builder historyBuilder;
|
@Inject HistoryEntry.Builder historyBuilder;
|
||||||
@Inject EppResponse.Builder responseBuilder;
|
@Inject EppResponse.Builder responseBuilder;
|
||||||
|
@Inject DomainCreateFlowCustomLogic customLogic;
|
||||||
@Inject DomainCreateFlow() {}
|
@Inject DomainCreateFlow() {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -198,6 +202,12 @@ public class DomainCreateFlow implements TransactionalFlow {
|
||||||
if (hasSignedMarks) {
|
if (hasSignedMarks) {
|
||||||
verifySignedMarksAllowed(tldState, isAnchorTenant);
|
verifySignedMarksAllowed(tldState, isAnchorTenant);
|
||||||
}
|
}
|
||||||
|
customLogic.afterValidation(
|
||||||
|
DomainCreateFlowCustomLogic.AfterValidationParameters.newBuilder()
|
||||||
|
.setDomainName(domainName)
|
||||||
|
.setYears(years)
|
||||||
|
.build());
|
||||||
|
|
||||||
FeeCreateCommandExtension feeCreate =
|
FeeCreateCommandExtension feeCreate =
|
||||||
eppInput.getSingleExtension(FeeCreateCommandExtension.class);
|
eppInput.getSingleExtension(FeeCreateCommandExtension.class);
|
||||||
EppCommandOperations commandOperations = TldSpecificLogicProxy.getCreatePrice(
|
EppCommandOperations commandOperations = TldSpecificLogicProxy.getCreatePrice(
|
||||||
|
@ -269,7 +279,6 @@ public class DomainCreateFlow implements TransactionalFlow {
|
||||||
.setContacts(command.getContacts())
|
.setContacts(command.getContacts())
|
||||||
.addGracePeriod(GracePeriod.forBillingEvent(GracePeriodStatus.ADD, createBillingEvent))
|
.addGracePeriod(GracePeriod.forBillingEvent(GracePeriodStatus.ADD, createBillingEvent))
|
||||||
.build();
|
.build();
|
||||||
handleExtraFlowLogic(registry.getTldStr(), years, historyEntry, newDomain);
|
|
||||||
entitiesToSave.add(
|
entitiesToSave.add(
|
||||||
newDomain,
|
newDomain,
|
||||||
ForeignKeyIndex.create(newDomain, newDomain.getDeletionTime()),
|
ForeignKeyIndex.create(newDomain, newDomain.getDeletionTime()),
|
||||||
|
@ -282,7 +291,29 @@ public class DomainCreateFlow implements TransactionalFlow {
|
||||||
prepareMarkedLrpTokenEntity(authInfo.getPw().getValue(), domainName, historyEntry));
|
prepareMarkedLrpTokenEntity(authInfo.getPw().getValue(), domainName, historyEntry));
|
||||||
}
|
}
|
||||||
enqueueTasks(hasSignedMarks, hasClaimsNotice, newDomain);
|
enqueueTasks(hasSignedMarks, hasClaimsNotice, newDomain);
|
||||||
ofy().save().entities(entitiesToSave.build());
|
|
||||||
|
// TODO: Remove this section and only use the customLogic.
|
||||||
|
Optional<RegistryExtraFlowLogic> extraFlowLogic =
|
||||||
|
RegistryExtraFlowLogicProxy.newInstanceForTld(registry.getTldStr());
|
||||||
|
if (extraFlowLogic.isPresent()) {
|
||||||
|
extraFlowLogic.get().performAdditionalDomainCreateLogic(
|
||||||
|
newDomain,
|
||||||
|
clientId,
|
||||||
|
years,
|
||||||
|
eppInput,
|
||||||
|
historyEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityChanges entityChanges =
|
||||||
|
customLogic.beforeSave(
|
||||||
|
DomainCreateFlowCustomLogic.BeforeSaveParameters.newBuilder()
|
||||||
|
.setNewDomain(newDomain)
|
||||||
|
.setHistoryEntry(historyEntry)
|
||||||
|
.setYears(years)
|
||||||
|
.build(),
|
||||||
|
EntityChanges.newBuilder().setSaves(entitiesToSave.build()).build());
|
||||||
|
persistEntityChanges(entityChanges);
|
||||||
|
|
||||||
return responseBuilder
|
return responseBuilder
|
||||||
.setResData(DomainCreateData.create(targetId, now, registrationExpirationTime))
|
.setResData(DomainCreateData.create(targetId, now, registrationExpirationTime))
|
||||||
.setExtensions(createResponseExtensions(feeCreate, commandOperations))
|
.setExtensions(createResponseExtensions(feeCreate, commandOperations))
|
||||||
|
@ -395,21 +426,6 @@ public class DomainCreateFlow implements TransactionalFlow {
|
||||||
return registry.getLrpPeriod().contains(now) && !isAnchorTenant;
|
return registry.getLrpPeriod().contains(now) && !isAnchorTenant;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleExtraFlowLogic(
|
|
||||||
String tld, int years, HistoryEntry historyEntry, DomainResource newDomain)
|
|
||||||
throws EppException {
|
|
||||||
Optional<RegistryExtraFlowLogic> extraFlowLogic =
|
|
||||||
RegistryExtraFlowLogicProxy.newInstanceForTld(tld);
|
|
||||||
if (extraFlowLogic.isPresent()) {
|
|
||||||
extraFlowLogic.get().performAdditionalDomainCreateLogic(
|
|
||||||
newDomain,
|
|
||||||
clientId,
|
|
||||||
years,
|
|
||||||
eppInput,
|
|
||||||
historyEntry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void enqueueTasks(
|
private void enqueueTasks(
|
||||||
boolean hasSignedMarks, boolean hasClaimsNotice, DomainResource newDomain) {
|
boolean hasSignedMarks, boolean hasClaimsNotice, DomainResource newDomain) {
|
||||||
if (newDomain.shouldPublishToDns()) {
|
if (newDomain.shouldPublishToDns()) {
|
||||||
|
|
|
@ -17,6 +17,7 @@ package google.registry.module.frontend;
|
||||||
import dagger.Component;
|
import dagger.Component;
|
||||||
import google.registry.braintree.BraintreeModule;
|
import google.registry.braintree.BraintreeModule;
|
||||||
import google.registry.config.ConfigModule;
|
import google.registry.config.ConfigModule;
|
||||||
|
import google.registry.flows.custom.CustomLogicFactoryModule;
|
||||||
import google.registry.keyring.api.DummyKeyringModule;
|
import google.registry.keyring.api.DummyKeyringModule;
|
||||||
import google.registry.keyring.api.KeyModule;
|
import google.registry.keyring.api.KeyModule;
|
||||||
import google.registry.module.frontend.FrontendRequestComponent.FrontendRequestComponentModule;
|
import google.registry.module.frontend.FrontendRequestComponent.FrontendRequestComponentModule;
|
||||||
|
@ -40,6 +41,7 @@ import javax.inject.Singleton;
|
||||||
BraintreeModule.class,
|
BraintreeModule.class,
|
||||||
ConfigModule.class,
|
ConfigModule.class,
|
||||||
ConsoleConfigModule.class,
|
ConsoleConfigModule.class,
|
||||||
|
CustomLogicFactoryModule.class,
|
||||||
DummyKeyringModule.class,
|
DummyKeyringModule.class,
|
||||||
FrontendMetricsModule.class,
|
FrontendMetricsModule.class,
|
||||||
FrontendRequestComponentModule.class,
|
FrontendRequestComponentModule.class,
|
||||||
|
|
|
@ -17,6 +17,7 @@ package google.registry.module.tools;
|
||||||
import dagger.Component;
|
import dagger.Component;
|
||||||
import google.registry.config.ConfigModule;
|
import google.registry.config.ConfigModule;
|
||||||
import google.registry.export.DriveModule;
|
import google.registry.export.DriveModule;
|
||||||
|
import google.registry.flows.custom.CustomLogicFactoryModule;
|
||||||
import google.registry.gcs.GcsServiceModule;
|
import google.registry.gcs.GcsServiceModule;
|
||||||
import google.registry.groups.DirectoryModule;
|
import google.registry.groups.DirectoryModule;
|
||||||
import google.registry.groups.GroupsModule;
|
import google.registry.groups.GroupsModule;
|
||||||
|
@ -42,6 +43,7 @@ import javax.inject.Singleton;
|
||||||
modules = {
|
modules = {
|
||||||
AppIdentityCredentialModule.class,
|
AppIdentityCredentialModule.class,
|
||||||
ConfigModule.class,
|
ConfigModule.class,
|
||||||
|
CustomLogicFactoryModule.class,
|
||||||
DatastoreServiceModule.class,
|
DatastoreServiceModule.class,
|
||||||
DirectoryModule.class,
|
DirectoryModule.class,
|
||||||
DriveModule.class,
|
DriveModule.class,
|
||||||
|
|
|
@ -56,6 +56,28 @@ public class TypeUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the class referred to by a fully qualified class name string.
|
||||||
|
*
|
||||||
|
* <p>Throws an error if the loaded class is not assignable from the expected super type class.
|
||||||
|
*/
|
||||||
|
public static <T> Class<T> getClassFromString(String className, Class<T> expectedSuperType) {
|
||||||
|
Class<?> clazz;
|
||||||
|
try {
|
||||||
|
clazz = Class.forName(className);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new IllegalArgumentException(String.format("Failed to load class %s", className), e);
|
||||||
|
}
|
||||||
|
checkArgument(
|
||||||
|
expectedSuperType.isAssignableFrom(clazz),
|
||||||
|
"%s does not implement/extend %s",
|
||||||
|
clazz.getSimpleName(),
|
||||||
|
expectedSuperType.getSimpleName());
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Class<T> castedClass = (Class<T>) clazz;
|
||||||
|
return castedClass;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aggregates enum "values" in a typesafe enum pattern into a string->field map.
|
* Aggregates enum "values" in a typesafe enum pattern into a string->field map.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -23,6 +23,7 @@ import dagger.Provides;
|
||||||
import dagger.Subcomponent;
|
import dagger.Subcomponent;
|
||||||
import google.registry.config.ConfigModule;
|
import google.registry.config.ConfigModule;
|
||||||
import google.registry.dns.DnsQueue;
|
import google.registry.dns.DnsQueue;
|
||||||
|
import google.registry.flows.custom.CustomLogicFactoryModule;
|
||||||
import google.registry.monitoring.whitebox.BigQueryMetricsEnqueuer;
|
import google.registry.monitoring.whitebox.BigQueryMetricsEnqueuer;
|
||||||
import google.registry.monitoring.whitebox.EppMetric;
|
import google.registry.monitoring.whitebox.EppMetric;
|
||||||
import google.registry.request.RequestScope;
|
import google.registry.request.RequestScope;
|
||||||
|
@ -35,6 +36,7 @@ import javax.inject.Singleton;
|
||||||
@Component(
|
@Component(
|
||||||
modules = {
|
modules = {
|
||||||
ConfigModule.class,
|
ConfigModule.class,
|
||||||
|
CustomLogicFactoryModule.class,
|
||||||
EppTestComponent.FakesAndMocksModule.class
|
EppTestComponent.FakesAndMocksModule.class
|
||||||
})
|
})
|
||||||
interface EppTestComponent {
|
interface EppTestComponent {
|
||||||
|
|
53
javatests/google/registry/util/TypeUtilsTest.java
Normal file
53
javatests/google/registry/util/TypeUtilsTest.java
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
// Copyright 2016 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.util;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import google.registry.testing.ExceptionRule;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.JUnit4;
|
||||||
|
|
||||||
|
/** Unit tests for {@link TypeUtils}. */
|
||||||
|
@RunWith(JUnit4.class)
|
||||||
|
public class TypeUtilsTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final ExceptionRule thrown = new ExceptionRule();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_getClassFromString_validClass() {
|
||||||
|
Class<? extends Serializable> clazz =
|
||||||
|
TypeUtils.<Serializable>getClassFromString("java.util.ArrayList", Serializable.class);
|
||||||
|
assertThat(clazz).isEqualTo(ArrayList.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_getClassFromString_notAssignableFrom() {
|
||||||
|
thrown.expect(IllegalArgumentException.class, "ArrayList does not implement/extend Integer");
|
||||||
|
TypeUtils.<Integer>getClassFromString("java.util.ArrayList", Integer.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_getClassFromString_unknownClass() {
|
||||||
|
thrown.expect(
|
||||||
|
IllegalArgumentException.class, "Failed to load class com.fake.company.nonexistent.Class");
|
||||||
|
TypeUtils.<Object>getClassFromString("com.fake.company.nonexistent.Class", Object.class);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue