diff --git a/java/google/registry/flows/Flow.java b/java/google/registry/flows/Flow.java
index 154b32ff8..c19ab5546 100644
--- a/java/google/registry/flows/Flow.java
+++ b/java/google/registry/flows/Flow.java
@@ -14,90 +14,24 @@
package google.registry.flows;
-import com.google.common.collect.ImmutableList;
-import google.registry.model.eppcommon.Trid;
-import google.registry.model.eppinput.EppInput;
-import google.registry.model.eppoutput.EppOutput;
-import google.registry.model.eppoutput.EppResponse;
-import google.registry.model.eppoutput.EppResponse.ResponseData;
-import google.registry.model.eppoutput.EppResponse.ResponseExtension;
-import google.registry.model.eppoutput.Result;
-import google.registry.model.poll.MessageQueueInfo;
-import javax.annotation.Nullable;
-import org.joda.time.DateTime;
+import google.registry.model.eppoutput.EppOutput.ResponseOrGreeting;
/**
- * An abstract EPP flow.
+ * An Extensible Provisioning Protocol flow.
*
- *
This class also contains static methods for loading an appropriate flow based on model
- * classes.
+ *
A "flow" is our word for a "command", since we've overloaded the word "command" to mean the
+ * command objects and also the CLI operation classes.
*/
-public abstract class Flow {
-
- protected EppInput eppInput;
- protected SessionMetadata sessionMetadata;
- protected TransportCredentials credentials;
- protected Trid trid;
- protected DateTime now;
-
- /** Whether this flow is being run in a superuser mode that can skip some checks. */
- protected boolean isSuperuser;
-
- /** Flows can override this for custom initialization. */
- @SuppressWarnings("unused")
- protected void initFlow() throws EppException {}
-
- /** Execute the business logic for this flow. */
- protected abstract EppOutput run() throws EppException;
-
- protected EppOutput createOutput(Result.Code code) {
- return createOutput(code, null);
- }
-
- protected EppOutput createOutput(Result.Code code, ResponseData responseData) {
- return createOutput(code, responseData, null);
- }
-
- protected EppOutput createOutput(
- Result.Code code,
- @Nullable ResponseData responseData,
- @Nullable ImmutableList extends ResponseExtension> extensions) {
- return createOutput(
- code, responseData == null ? null : ImmutableList.of(responseData), extensions, null);
- }
-
- protected EppOutput createOutput(
- Result.Code code,
- @Nullable ImmutableList responseData,
- @Nullable ImmutableList extends ResponseExtension> responseExtensions,
- @Nullable MessageQueueInfo messageQueueInfo) {
- return EppOutput.create(new EppResponse.Builder()
- .setTrid(trid)
- .setResult(Result.create(code))
- .setMessageQueueInfo(messageQueueInfo)
- .setResData(responseData)
- .setExtensions(responseExtensions)
- .build());
- }
+public interface Flow {
/**
- * Using an init function instead of a constructor avoids duplicating constructors across the
- * entire hierarchy of flow classes
+ * Executes an EPP "flow" and returns a response object (or in the specific case of the "hello"
+ * flow a greeting object) that can be converted to XML and returned to the caller.
+ *
+ * Flows should have {@link #run} called once per instance. If a flow needs to be retried, a
+ * new instance should be created.
+ *
+ *
Flows should get all of their parameters via injection off of {@link FlowComponent}.
*/
- public final Flow init(
- EppInput eppInput,
- Trid trid,
- SessionMetadata sessionMetadata,
- TransportCredentials credentials,
- boolean isSuperuser,
- DateTime now) throws EppException {
- this.eppInput = eppInput;
- this.trid = trid;
- this.sessionMetadata = sessionMetadata;
- this.credentials = credentials;
- this.now = now;
- this.isSuperuser = isSuperuser;
- initFlow();
- return this;
- }
+ ResponseOrGreeting run() throws EppException;
}
diff --git a/java/google/registry/flows/FlowModule.java b/java/google/registry/flows/FlowModule.java
index bfe92367d..72b556e29 100644
--- a/java/google/registry/flows/FlowModule.java
+++ b/java/google/registry/flows/FlowModule.java
@@ -31,6 +31,8 @@ import google.registry.model.eppinput.EppInput.Poll;
import google.registry.model.eppinput.EppInput.ResourceCommandWrapper;
import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppinput.ResourceCommand.SingleResourceCommand;
+import google.registry.model.eppoutput.EppResponse;
+import google.registry.model.eppoutput.Result;
import google.registry.model.reporting.HistoryEntry;
import java.lang.annotation.Documented;
import javax.inject.Qualifier;
@@ -244,6 +246,19 @@ public class FlowModule {
return historyBuilder;
}
+ /**
+ * Provides a partially filled in {@link EppResponse} builder.
+ *
+ *
This is not marked with {@link FlowScope} so that each retry gets a fresh one. Otherwise,
+ * the fact that the builder is one-use would cause NPEs.
+ */
+ @Provides
+ static EppResponse.Builder provideEppResponseBuilder(Trid trid) {
+ return new EppResponse.Builder()
+ .setTrid(trid)
+ .setResultFromCode(Result.Code.SUCCESS); // Default to success.
+ }
+
/** Wrapper class to carry an {@link EppException} to the calling code. */
static class EppExceptionInProviderException extends RuntimeException {
EppExceptionInProviderException(EppException exception) {
diff --git a/java/google/registry/flows/FlowRunner.java b/java/google/registry/flows/FlowRunner.java
index bce5bf9f7..0956f7f91 100644
--- a/java/google/registry/flows/FlowRunner.java
+++ b/java/google/registry/flows/FlowRunner.java
@@ -28,14 +28,11 @@ import google.registry.flows.FlowModule.InputXml;
import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.Transactional;
import google.registry.model.eppcommon.Trid;
-import google.registry.model.eppinput.EppInput;
import google.registry.model.eppoutput.EppOutput;
import google.registry.monitoring.whitebox.EppMetric;
-import google.registry.util.Clock;
import google.registry.util.FormattingLogger;
import javax.inject.Inject;
import javax.inject.Provider;
-import org.joda.time.DateTime;
import org.json.simple.JSONValue;
/** Run a flow, either transactionally or not, with logging and retrying as needed. */
@@ -56,9 +53,7 @@ public class FlowRunner {
private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass();
@Inject @ClientId String clientId;
- @Inject Clock clock;
@Inject TransportCredentials credentials;
- @Inject EppInput eppInput;
@Inject EppRequestSource eppRequestSource;
@Inject Provider flowProvider;
@Inject @InputXml byte[] inputXmlBytes;
@@ -99,7 +94,7 @@ public class FlowRunner {
"xmlBytes", xmlBase64)));
if (!isTransactional) {
metric.incrementAttempts();
- return createAndInitFlow(clock.nowUtc()).run();
+ return EppOutput.create(flowProvider.get().run());
}
try {
return ofy().transact(new Work() {
@@ -107,7 +102,7 @@ public class FlowRunner {
public EppOutput run() {
metric.incrementAttempts();
try {
- EppOutput output = createAndInitFlow(ofy().getTransactionTime()).run();
+ EppOutput output = EppOutput.create(flowProvider.get().run());
if (isDryRun) {
throw new DryRunException(output);
}
@@ -127,15 +122,6 @@ public class FlowRunner {
}
}
- private Flow createAndInitFlow(DateTime now) throws EppException {
- return flowProvider.get().init(
- eppInput,
- trid,
- sessionMetadata,
- credentials,
- isSuperuser,
- now);
- }
/** Exception for canceling a transaction while capturing what the output would have been. */
private static class DryRunException extends RuntimeException {
final EppOutput output;
diff --git a/java/google/registry/flows/TransactionalFlow.java b/java/google/registry/flows/TransactionalFlow.java
index 0c3aa089d..a228cca57 100644
--- a/java/google/registry/flows/TransactionalFlow.java
+++ b/java/google/registry/flows/TransactionalFlow.java
@@ -15,9 +15,9 @@
package google.registry.flows;
/**
- * Marker interface indicating that a {@link Flow} needs to be run transactionally.
+ * Interface for a {@link Flow} that needs to be run transactionally.
*
- * Any flow that mutates the datastore should be tagged with this so that {@link FlowRunner} will
- * know how to run it.
+ *
Any flow that mutates the datastore should implement this so that {@link FlowRunner} will know
+ * how to run it.
*/
-public interface TransactionalFlow {}
+public interface TransactionalFlow extends Flow {}
diff --git a/java/google/registry/flows/contact/ContactCheckFlow.java b/java/google/registry/flows/contact/ContactCheckFlow.java
index 4897837db..0b3329347 100644
--- a/java/google/registry/flows/contact/ContactCheckFlow.java
+++ b/java/google/registry/flows/contact/ContactCheckFlow.java
@@ -17,7 +17,6 @@ package google.registry.flows.contact;
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.verifyTargetIdCount;
import static google.registry.model.EppResourceUtils.checkResourcesExist;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import com.google.common.collect.ImmutableList;
import google.registry.config.ConfigModule.Config;
@@ -30,7 +29,8 @@ import google.registry.model.contact.ContactResource;
import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppoutput.CheckData.ContactCheck;
import google.registry.model.eppoutput.CheckData.ContactCheckData;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
+import google.registry.util.Clock;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
@@ -42,26 +42,28 @@ import javax.inject.Inject;
*
* @error {@link google.registry.flows.exceptions.TooManyResourceChecksException}
*/
-public final class ContactCheckFlow extends Flow {
+public final class ContactCheckFlow implements Flow {
@Inject ResourceCommand resourceCommand;
@Inject @ClientId String clientId;
@Inject ExtensionManager extensionManager;
+ @Inject Clock clock;
@Inject @Config("maxChecks") int maxChecks;
+ @Inject EppResponse.Builder responseBuilder;
@Inject ContactCheckFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.validate(); // There are no legal extensions for this flow.
validateClientIsLoggedIn(clientId);
List targetIds = ((Check) resourceCommand).getTargetIds();
verifyTargetIdCount(targetIds, maxChecks);
- Set existingIds = checkResourcesExist(ContactResource.class, targetIds, now);
+ Set existingIds = checkResourcesExist(ContactResource.class, targetIds, clock.nowUtc());
ImmutableList.Builder checks = new ImmutableList.Builder<>();
for (String id : targetIds) {
boolean unused = !existingIds.contains(id);
checks.add(ContactCheck.create(unused, id, unused ? null : "In use"));
}
- return createOutput(SUCCESS, ContactCheckData.create(checks.build()));
+ return responseBuilder.setResData(ContactCheckData.create(checks.build())).build();
}
}
diff --git a/java/google/registry/flows/contact/ContactCreateFlow.java b/java/google/registry/flows/contact/ContactCreateFlow.java
index 592472e42..ecf4d1d38 100644
--- a/java/google/registry/flows/contact/ContactCreateFlow.java
+++ b/java/google/registry/flows/contact/ContactCreateFlow.java
@@ -19,13 +19,11 @@ import static google.registry.flows.ResourceFlowUtils.verifyResourceDoesNotExist
import static google.registry.flows.contact.ContactFlowUtils.validateAsciiPostalInfo;
import static google.registry.flows.contact.ContactFlowUtils.validateContactAgainstPolicy;
import static google.registry.model.EppResourceUtils.createContactHostRoid;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.ofy.ObjectifyService.ofy;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
@@ -35,12 +33,13 @@ import google.registry.model.contact.ContactResource.Builder;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppoutput.CreateData.ContactCreateData;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.index.EppResourceIndex;
import google.registry.model.index.ForeignKeyIndex;
import google.registry.model.ofy.ObjectifyService;
import google.registry.model.reporting.HistoryEntry;
import javax.inject.Inject;
+import org.joda.time.DateTime;
/**
* An EPP flow that creates a new contact.
@@ -49,21 +48,23 @@ import javax.inject.Inject;
* @error {@link ContactFlowUtils.BadInternationalizedPostalInfoException}
* @error {@link ContactFlowUtils.DeclineContactDisclosureFieldDisallowedPolicyException}
*/
-public final class ContactCreateFlow extends Flow implements TransactionalFlow {
+public final class ContactCreateFlow implements TransactionalFlow {
@Inject ResourceCommand resourceCommand;
@Inject ExtensionManager extensionManager;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject HistoryEntry.Builder historyBuilder;
+ @Inject EppResponse.Builder responseBuilder;
@Inject ContactCreateFlow() {}
@Override
- protected final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(MetadataExtension.class);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
Create command = (Create) resourceCommand;
+ DateTime now = ofy().getTransactionTime();
verifyResourceDoesNotExist(ContactResource.class, targetId, now);
ContactResource newContact = new Builder()
.setContactId(targetId)
@@ -90,6 +91,8 @@ public final class ContactCreateFlow extends Flow implements TransactionalFlow {
historyBuilder.build(),
ForeignKeyIndex.create(newContact, newContact.getDeletionTime()),
EppResourceIndex.create(Key.create(newContact)));
- return createOutput(SUCCESS, ContactCreateData.create(newContact.getContactId(), now));
+ return responseBuilder
+ .setResData(ContactCreateData.create(newContact.getContactId(), now))
+ .build();
}
}
diff --git a/java/google/registry/flows/contact/ContactDeleteFlow.java b/java/google/registry/flows/contact/ContactDeleteFlow.java
index 0e057f29b..13600b7f7 100644
--- a/java/google/registry/flows/contact/ContactDeleteFlow.java
+++ b/java/google/registry/flows/contact/ContactDeleteFlow.java
@@ -29,8 +29,8 @@ import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
+import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.async.AsyncFlowEnqueuer;
@@ -39,9 +39,10 @@ import google.registry.model.domain.DomainBase;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppcommon.StatusValue;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.reporting.HistoryEntry;
import javax.inject.Inject;
+import org.joda.time.DateTime;
/**
* An EPP flow that deletes a contact.
@@ -57,7 +58,7 @@ import javax.inject.Inject;
* @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException}
* @error {@link google.registry.flows.exceptions.ResourceToDeleteIsReferencedException}
*/
-public final class ContactDeleteFlow extends Flow implements TransactionalFlow {
+public final class ContactDeleteFlow implements TransactionalFlow {
private static final ImmutableSet DISALLOWED_STATUSES = ImmutableSet.of(
StatusValue.LINKED,
@@ -75,16 +76,19 @@ public final class ContactDeleteFlow extends Flow implements TransactionalFlow {
@Inject ExtensionManager extensionManager;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
+ @Inject @Superuser boolean isSuperuser;
@Inject Optional authInfo;
@Inject HistoryEntry.Builder historyBuilder;
@Inject AsyncFlowEnqueuer asyncFlowEnqueuer;
+ @Inject EppResponse.Builder responseBuilder;
@Inject ContactDeleteFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(MetadataExtension.class);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
+ DateTime now = ofy().getTransactionTime();
failfastForAsyncDelete(targetId, now, ContactResource.class, GET_REFERENCED_CONTACTS);
ContactResource existingContact = loadAndVerifyExistence(ContactResource.class, targetId, now);
verifyNoDisallowedStatuses(existingContact, DISALLOWED_STATUSES);
@@ -100,6 +104,6 @@ public final class ContactDeleteFlow extends Flow implements TransactionalFlow {
.setModificationTime(now)
.setParent(Key.create(existingContact));
ofy().save().entities(newContact, historyBuilder.build());
- return createOutput(SUCCESS_WITH_ACTION_PENDING);
+ return responseBuilder.setResultFromCode(SUCCESS_WITH_ACTION_PENDING).build();
}
}
diff --git a/java/google/registry/flows/contact/ContactInfoFlow.java b/java/google/registry/flows/contact/ContactInfoFlow.java
index efc06b677..194a5cc87 100644
--- a/java/google/registry/flows/contact/ContactInfoFlow.java
+++ b/java/google/registry/flows/contact/ContactInfoFlow.java
@@ -18,7 +18,6 @@ import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
import static google.registry.model.EppResourceUtils.cloneResourceWithLinkedStatus;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import com.google.common.base.Optional;
import google.registry.flows.EppException;
@@ -28,8 +27,10 @@ import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.model.contact.ContactResource;
import google.registry.model.eppcommon.AuthInfo;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
+import google.registry.util.Clock;
import javax.inject.Inject;
+import org.joda.time.DateTime;
/**
* An EPP flow that returns information about a contact.
@@ -41,16 +42,19 @@ import javax.inject.Inject;
*
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
*/
-public final class ContactInfoFlow extends Flow {
+public final class ContactInfoFlow implements Flow {
@Inject ExtensionManager extensionManager;
+ @Inject Clock clock;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject Optional authInfo;
+ @Inject EppResponse.Builder responseBuilder;
@Inject ContactInfoFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
+ DateTime now = clock.nowUtc();
extensionManager.validate(); // There are no legal extensions for this flow.
validateClientIsLoggedIn(clientId);
ContactResource contact = loadAndVerifyExistence(ContactResource.class, targetId, now);
@@ -58,6 +62,6 @@ public final class ContactInfoFlow extends Flow {
if (!clientId.equals(contact.getCurrentSponsorClientId()) && !authInfo.isPresent()) {
contact = contact.asBuilder().setAuthInfo(null).build();
}
- return createOutput(SUCCESS, cloneResourceWithLinkedStatus(contact, now));
+ return responseBuilder.setResData(cloneResourceWithLinkedStatus(contact, now)).build();
}
}
diff --git a/java/google/registry/flows/contact/ContactTransferApproveFlow.java b/java/google/registry/flows/contact/ContactTransferApproveFlow.java
index 184a2b5bd..50002098c 100644
--- a/java/google/registry/flows/contact/ContactTransferApproveFlow.java
+++ b/java/google/registry/flows/contact/ContactTransferApproveFlow.java
@@ -21,14 +21,12 @@ import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForR
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
import static google.registry.flows.contact.ContactFlowUtils.createGainingTransferPollMessage;
import static google.registry.flows.contact.ContactFlowUtils.createTransferResponse;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.ofy.ObjectifyService.ofy;
import com.google.common.base.Optional;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
@@ -37,12 +35,13 @@ import google.registry.model.contact.ContactResource;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppinput.ResourceCommand;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferStatus;
import javax.inject.Inject;
+import org.joda.time.DateTime;
/**
* An EPP flow that approves a pending transfer on a contact.
@@ -57,7 +56,7 @@ import javax.inject.Inject;
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
* @error {@link google.registry.flows.exceptions.NotPendingTransferException}
*/
-public final class ContactTransferApproveFlow extends Flow implements TransactionalFlow {
+public final class ContactTransferApproveFlow implements TransactionalFlow {
@Inject ResourceCommand resourceCommand;
@Inject ExtensionManager extensionManager;
@@ -65,6 +64,7 @@ public final class ContactTransferApproveFlow extends Flow implements Transactio
@Inject @TargetId String targetId;
@Inject Optional authInfo;
@Inject HistoryEntry.Builder historyBuilder;
+ @Inject EppResponse.Builder responseBuilder;
@Inject ContactTransferApproveFlow() {}
/**
@@ -72,10 +72,11 @@ public final class ContactTransferApproveFlow extends Flow implements Transactio
* {@link ContactResource#cloneProjectedAtTime} which handles implicit server approvals.
*/
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(MetadataExtension.class);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
+ DateTime now = ofy().getTransactionTime();
ContactResource existingContact = loadAndVerifyExistence(ContactResource.class, targetId, now);
verifyOptionalAuthInfoForResource(authInfo, existingContact);
TransferData transferData = existingContact.getTransferData();
@@ -97,6 +98,8 @@ public final class ContactTransferApproveFlow extends Flow implements Transactio
// Delete the billing event and poll messages that were written in case the transfer would have
// been implicitly server approved.
ofy().delete().keys(transferData.getServerApproveEntities());
- return createOutput(SUCCESS, createTransferResponse(targetId, newContact.getTransferData()));
+ return responseBuilder
+ .setResData(createTransferResponse(targetId, newContact.getTransferData()))
+ .build();
}
}
diff --git a/java/google/registry/flows/contact/ContactTransferCancelFlow.java b/java/google/registry/flows/contact/ContactTransferCancelFlow.java
index b7413c3da..5e61789cc 100644
--- a/java/google/registry/flows/contact/ContactTransferCancelFlow.java
+++ b/java/google/registry/flows/contact/ContactTransferCancelFlow.java
@@ -20,14 +20,12 @@ import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
import static google.registry.flows.contact.ContactFlowUtils.createLosingTransferPollMessage;
import static google.registry.flows.contact.ContactFlowUtils.createTransferResponse;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.ofy.ObjectifyService.ofy;
import com.google.common.base.Optional;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
@@ -37,12 +35,13 @@ import google.registry.model.contact.ContactResource;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppinput.ResourceCommand;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferStatus;
import javax.inject.Inject;
+import org.joda.time.DateTime;
/**
* An EPP flow that cancels a pending transfer on a contact.
@@ -57,7 +56,7 @@ import javax.inject.Inject;
* @error {@link google.registry.flows.exceptions.NotPendingTransferException}
* @error {@link google.registry.flows.exceptions.NotTransferInitiatorException}
*/
-public final class ContactTransferCancelFlow extends Flow implements TransactionalFlow {
+public final class ContactTransferCancelFlow implements TransactionalFlow {
@Inject ResourceCommand resourceCommand;
@Inject ExtensionManager extensionManager;
@@ -65,13 +64,15 @@ public final class ContactTransferCancelFlow extends Flow implements Transaction
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject HistoryEntry.Builder historyBuilder;
+ @Inject EppResponse.Builder responseBuilder;
@Inject ContactTransferCancelFlow() {}
@Override
- protected final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(MetadataExtension.class);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
+ DateTime now = ofy().getTransactionTime();
ContactResource existingContact = loadAndVerifyExistence(ContactResource.class, targetId, now);
verifyOptionalAuthInfoForResource(authInfo, existingContact);
TransferData transferData = existingContact.getTransferData();
@@ -95,6 +96,8 @@ public final class ContactTransferCancelFlow extends Flow implements Transaction
// Delete the billing event and poll messages that were written in case the transfer would have
// been implicitly server approved.
ofy().delete().keys(transferData.getServerApproveEntities());
- return createOutput(SUCCESS, createTransferResponse(targetId, newContact.getTransferData()));
+ return responseBuilder
+ .setResData(createTransferResponse(targetId, newContact.getTransferData()))
+ .build();
}
}
diff --git a/java/google/registry/flows/contact/ContactTransferQueryFlow.java b/java/google/registry/flows/contact/ContactTransferQueryFlow.java
index 30c6c1828..5bcd0ad19 100644
--- a/java/google/registry/flows/contact/ContactTransferQueryFlow.java
+++ b/java/google/registry/flows/contact/ContactTransferQueryFlow.java
@@ -18,7 +18,6 @@ import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
import static google.registry.flows.contact.ContactFlowUtils.createTransferResponse;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import com.google.common.base.Optional;
import google.registry.flows.EppException;
@@ -30,7 +29,8 @@ import google.registry.flows.exceptions.NoTransferHistoryToQueryException;
import google.registry.flows.exceptions.NotAuthorizedToViewTransferException;
import google.registry.model.contact.ContactResource;
import google.registry.model.eppcommon.AuthInfo;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
+import google.registry.util.Clock;
import javax.inject.Inject;
/**
@@ -48,19 +48,22 @@ import javax.inject.Inject;
* @error {@link google.registry.flows.exceptions.NoTransferHistoryToQueryException}
* @error {@link google.registry.flows.exceptions.NotAuthorizedToViewTransferException}
*/
-public final class ContactTransferQueryFlow extends Flow {
+public final class ContactTransferQueryFlow implements Flow {
@Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
+ @Inject Clock clock;
+ @Inject EppResponse.Builder responseBuilder;
@Inject ContactTransferQueryFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.validate(); // There are no legal extensions for this flow.
validateClientIsLoggedIn(clientId);
- ContactResource contact = loadAndVerifyExistence(ContactResource.class, targetId, now);
+ ContactResource contact =
+ loadAndVerifyExistence(ContactResource.class, targetId, clock.nowUtc());
verifyOptionalAuthInfoForResource(authInfo, contact);
// Most of the fields on the transfer response are required, so there's no way to return valid
// XML if the object has never been transferred (and hence the fields aren't populated).
@@ -74,6 +77,8 @@ public final class ContactTransferQueryFlow extends Flow {
&& !clientId.equals(contact.getTransferData().getLosingClientId())) {
throw new NotAuthorizedToViewTransferException();
}
- return createOutput(SUCCESS, createTransferResponse(targetId, contact.getTransferData()));
+ return responseBuilder
+ .setResData(createTransferResponse(targetId, contact.getTransferData()))
+ .build();
}
}
diff --git a/java/google/registry/flows/contact/ContactTransferRejectFlow.java b/java/google/registry/flows/contact/ContactTransferRejectFlow.java
index 3ca325099..53efcac06 100644
--- a/java/google/registry/flows/contact/ContactTransferRejectFlow.java
+++ b/java/google/registry/flows/contact/ContactTransferRejectFlow.java
@@ -21,14 +21,12 @@ import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForR
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
import static google.registry.flows.contact.ContactFlowUtils.createGainingTransferPollMessage;
import static google.registry.flows.contact.ContactFlowUtils.createTransferResponse;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.ofy.ObjectifyService.ofy;
import com.google.common.base.Optional;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
@@ -36,12 +34,13 @@ import google.registry.flows.exceptions.NotPendingTransferException;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppcommon.AuthInfo;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferStatus;
import javax.inject.Inject;
+import org.joda.time.DateTime;
/**
* An EPP flow that rejects a pending transfer on a contact.
@@ -56,20 +55,22 @@ import javax.inject.Inject;
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}
* @error {@link google.registry.flows.exceptions.NotPendingTransferException}
*/
-public final class ContactTransferRejectFlow extends Flow implements TransactionalFlow {
+public final class ContactTransferRejectFlow implements TransactionalFlow {
@Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject HistoryEntry.Builder historyBuilder;
+ @Inject EppResponse.Builder responseBuilder;
@Inject ContactTransferRejectFlow() {}
@Override
- protected final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(MetadataExtension.class);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
+ DateTime now = ofy().getTransactionTime();
ContactResource existingContact = loadAndVerifyExistence(ContactResource.class, targetId, now);
verifyOptionalAuthInfoForResource(authInfo, existingContact);
TransferData transferData = existingContact.getTransferData();
@@ -90,6 +91,8 @@ public final class ContactTransferRejectFlow extends Flow implements Transaction
// Delete the billing event and poll messages that were written in case the transfer would have
// been implicitly server approved.
ofy().delete().keys(transferData.getServerApproveEntities());
- return createOutput(SUCCESS, createTransferResponse(targetId, newContact.getTransferData()));
+ return responseBuilder
+ .setResData(createTransferResponse(targetId, newContact.getTransferData()))
+ .build();
}
}
diff --git a/java/google/registry/flows/contact/ContactTransferRequestFlow.java b/java/google/registry/flows/contact/ContactTransferRequestFlow.java
index 53b2bac50..1975d2509 100644
--- a/java/google/registry/flows/contact/ContactTransferRequestFlow.java
+++ b/java/google/registry/flows/contact/ContactTransferRequestFlow.java
@@ -30,7 +30,6 @@ import com.googlecode.objectify.Key;
import google.registry.config.ConfigModule.Config;
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
@@ -40,7 +39,8 @@ import google.registry.model.contact.ContactResource;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppcommon.StatusValue;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppcommon.Trid;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.TransferData;
@@ -64,7 +64,7 @@ import org.joda.time.Duration;
* @error {@link google.registry.flows.exceptions.MissingTransferRequestAuthInfoException}
* @error {@link google.registry.flows.exceptions.ObjectAlreadySponsoredException}
*/
-public final class ContactTransferRequestFlow extends Flow implements TransactionalFlow {
+public final class ContactTransferRequestFlow implements TransactionalFlow {
private static final ImmutableSet DISALLOWED_STATUSES = ImmutableSet.of(
StatusValue.CLIENT_TRANSFER_PROHIBITED,
@@ -77,13 +77,16 @@ public final class ContactTransferRequestFlow extends Flow implements Transactio
@Inject @TargetId String targetId;
@Inject @Config("contactAutomaticTransferLength") Duration automaticTransferLength;
@Inject HistoryEntry.Builder historyBuilder;
+ @Inject Trid trid;
+ @Inject EppResponse.Builder responseBuilder;
@Inject ContactTransferRequestFlow() {}
@Override
- protected final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(MetadataExtension.class);
extensionManager.validate();
validateClientIsLoggedIn(gainingClientId);
+ DateTime now = ofy().getTransactionTime();
ContactResource existingContact = loadAndVerifyExistence(ContactResource.class, targetId, now);
verifyRequiredAuthInfoForResourceTransfer(authInfo, existingContact);
// Verify that the resource does not already have a pending transfer.
@@ -138,9 +141,10 @@ public final class ContactTransferRequestFlow extends Flow implements Transactio
requestPollMessage,
serverApproveGainingPollMessage,
serverApproveLosingPollMessage);
- return createOutput(
- SUCCESS_WITH_ACTION_PENDING,
- createTransferResponse(targetId, newContact.getTransferData()));
+ return responseBuilder
+ .setResultFromCode(SUCCESS_WITH_ACTION_PENDING)
+ .setResData(createTransferResponse(targetId, newContact.getTransferData()))
+ .build();
}
}
diff --git a/java/google/registry/flows/contact/ContactUpdateFlow.java b/java/google/registry/flows/contact/ContactUpdateFlow.java
index 7a8c032d4..21ebcec76 100644
--- a/java/google/registry/flows/contact/ContactUpdateFlow.java
+++ b/java/google/registry/flows/contact/ContactUpdateFlow.java
@@ -24,7 +24,6 @@ import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForR
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
import static google.registry.flows.contact.ContactFlowUtils.validateAsciiPostalInfo;
import static google.registry.flows.contact.ContactFlowUtils.validateContactAgainstPolicy;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.ofy.ObjectifyService.ofy;
import com.google.common.base.Optional;
@@ -32,8 +31,8 @@ import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
+import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException;
@@ -46,10 +45,11 @@ import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppinput.ResourceCommand;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.reporting.HistoryEntry;
import javax.annotation.Nullable;
import javax.inject.Inject;
+import org.joda.time.DateTime;
/**
* An EPP flow that updates a contact.
@@ -63,7 +63,7 @@ import javax.inject.Inject;
* @error {@link ContactFlowUtils.BadInternationalizedPostalInfoException}
* @error {@link ContactFlowUtils.DeclineContactDisclosureFieldDisallowedPolicyException}
*/
-public final class ContactUpdateFlow extends Flow implements TransactionalFlow {
+public final class ContactUpdateFlow implements TransactionalFlow {
/**
* Note that CLIENT_UPDATE_PROHIBITED is intentionally not in this list. This is because it
@@ -79,15 +79,18 @@ public final class ContactUpdateFlow extends Flow implements TransactionalFlow {
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
+ @Inject @Superuser boolean isSuperuser;
@Inject HistoryEntry.Builder historyBuilder;
+ @Inject EppResponse.Builder responseBuilder;
@Inject ContactUpdateFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(MetadataExtension.class);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
Update command = (Update) resourceCommand;
+ DateTime now = ofy().getTransactionTime();
ContactResource existingContact = loadAndVerifyExistence(ContactResource.class, targetId, now);
verifyOptionalAuthInfoForResource(authInfo, existingContact);
ImmutableSet statusToRemove = command.getInnerRemove().getStatusValues();
@@ -146,7 +149,7 @@ public final class ContactUpdateFlow extends Flow implements TransactionalFlow {
validateAsciiPostalInfo(newContact.getInternationalizedPostalInfo());
validateContactAgainstPolicy(newContact);
ofy().save().entities(newContact, historyBuilder.build());
- return createOutput(SUCCESS);
+ return responseBuilder.build();
}
/** Return the first non-null param, or null if both are null. */
diff --git a/java/google/registry/flows/domain/ClaimsCheckFlow.java b/java/google/registry/flows/domain/ClaimsCheckFlow.java
index cd02db10b..a81549c4b 100644
--- a/java/google/registry/flows/domain/ClaimsCheckFlow.java
+++ b/java/google/registry/flows/domain/ClaimsCheckFlow.java
@@ -22,7 +22,6 @@ import static google.registry.flows.domain.DomainFlowUtils.validateDomainNameWit
import static google.registry.flows.domain.DomainFlowUtils.verifyClaimsPeriodNotEnded;
import static google.registry.flows.domain.DomainFlowUtils.verifyNotInPredelegation;
import static google.registry.model.domain.launch.LaunchPhase.CLAIMS;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
@@ -33,20 +32,23 @@ import google.registry.flows.EppException.CommandUseErrorException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
+import google.registry.flows.FlowModule.Superuser;
import google.registry.model.domain.DomainCommand.Check;
import google.registry.model.domain.launch.LaunchCheckExtension;
import google.registry.model.domain.launch.LaunchCheckResponseExtension;
import google.registry.model.domain.launch.LaunchCheckResponseExtension.LaunchCheck;
import google.registry.model.domain.launch.LaunchCheckResponseExtension.LaunchCheckName;
import google.registry.model.eppinput.ResourceCommand;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.registry.Registry;
import google.registry.model.registry.Registry.TldState;
import google.registry.model.tmch.ClaimsListShard;
+import google.registry.util.Clock;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
+import org.joda.time.DateTime;
/**
* An EPP flow that checks whether strings are trademarked.
@@ -58,16 +60,19 @@ import javax.inject.Inject;
* @error {@link DomainFlowUtils.TldDoesNotExistException}
* @error {@link ClaimsCheckNotAllowedInSunrise}
*/
-public final class ClaimsCheckFlow extends Flow {
+public final class ClaimsCheckFlow implements Flow {
@Inject ExtensionManager extensionManager;
@Inject ResourceCommand resourceCommand;
@Inject @ClientId String clientId;
+ @Inject @Superuser boolean isSuperuser;
+ @Inject Clock clock;
@Inject @Config("maxChecks") int maxChecks;
+ @Inject EppResponse.Builder responseBuilder;
@Inject ClaimsCheckFlow() {}
@Override
- public EppOutput run() throws EppException {
+ public EppResponse run() throws EppException {
extensionManager.register(LaunchCheckExtension.class);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
@@ -84,6 +89,7 @@ public final class ClaimsCheckFlow extends Flow {
checkAllowedAccessToTld(clientId, tld);
Registry registry = Registry.get(tld);
if (!isSuperuser) {
+ DateTime now = clock.nowUtc();
verifyNotInPredelegation(registry, now);
if (registry.getTldState(now) == TldState.SUNRISE) {
throw new ClaimsCheckNotAllowedInSunrise();
@@ -96,10 +102,9 @@ public final class ClaimsCheckFlow extends Flow {
LaunchCheck.create(
LaunchCheckName.create(claimKey != null, targetId), claimKey));
}
- return createOutput(
- SUCCESS,
- null,
- ImmutableList.of(LaunchCheckResponseExtension.create(CLAIMS, launchChecksBuilder.build())));
+ return responseBuilder
+ .setOnlyExtension(LaunchCheckResponseExtension.create(CLAIMS, launchChecksBuilder.build()))
+ .build();
}
/** Claims checks are not allowed during sunrise. */
diff --git a/java/google/registry/flows/domain/DomainAllocateFlow.java b/java/google/registry/flows/domain/DomainAllocateFlow.java
index 6ec78e0c9..4ca97cf6b 100644
--- a/java/google/registry/flows/domain/DomainAllocateFlow.java
+++ b/java/google/registry/flows/domain/DomainAllocateFlow.java
@@ -48,8 +48,8 @@ import google.registry.flows.EppException.AuthorizationErrorException;
import google.registry.flows.EppException.ObjectDoesNotExistException;
import google.registry.flows.EppException.StatusProhibitsOperationException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
+import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.domain.TldSpecificLogicProxy.EppCommandOperations;
@@ -73,10 +73,10 @@ import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.secdns.SecDnsCreateExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppcommon.StatusValue;
+import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppoutput.CreateData.DomainCreateData;
-import google.registry.model.eppoutput.EppOutput;
-import google.registry.model.eppoutput.Result;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.index.EppResourceIndex;
import google.registry.model.index.ForeignKeyIndex;
import google.registry.model.ofy.ObjectifyService;
@@ -97,7 +97,7 @@ import org.joda.time.DateTime;
* @error {@link DomainAllocateFlow.MissingApplicationException}
* @error {@link DomainAllocateFlow.OnlySuperuserCanAllocateException}
*/
-public class DomainAllocateFlow extends Flow implements TransactionalFlow {
+public class DomainAllocateFlow implements TransactionalFlow {
private static final String COLLISION_MESSAGE =
"Domain on the name collision list was allocated. But by policy, the domain will not be "
@@ -109,11 +109,14 @@ public class DomainAllocateFlow extends Flow implements TransactionalFlow {
@Inject ResourceCommand resourceCommand;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
+ @Inject @Superuser boolean isSuperuser;
@Inject HistoryEntry.Builder historyBuilder;
+ @Inject EppInput eppInput;
+ @Inject EppResponse.Builder responseBuilder;
@Inject DomainAllocateFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(
SecDnsCreateExtension.class,
FlagsCreateCommandExtension.class,
@@ -123,6 +126,7 @@ public class DomainAllocateFlow extends Flow implements TransactionalFlow {
extensionManager.validate();
validateClientIsLoggedIn(clientId);
verifyIsSuperuser();
+ DateTime now = ofy().getTransactionTime();
Create command = cloneAndLinkReferences((Create) resourceCommand, now);
failfastForCreate(targetId, now);
verifyResourceDoesNotExist(DomainResource.class, targetId, now);
@@ -137,13 +141,14 @@ public class DomainAllocateFlow extends Flow implements TransactionalFlow {
boolean isSunrushAddGracePeriod = isNullOrEmpty(command.getNameservers());
AllocateCreateExtension allocateCreate =
eppInput.getSingleExtension(AllocateCreateExtension.class);
- DomainApplication application = loadAndValidateApplication(allocateCreate.getApplicationRoid());
+ DomainApplication application =
+ loadAndValidateApplication(allocateCreate.getApplicationRoid(), now);
String repoId = createDomainRoid(ObjectifyService.allocateId(), registry.getTldStr());
ImmutableSet.Builder entitiesToSave = new ImmutableSet.Builder<>();
- HistoryEntry historyEntry = buildHistory(repoId, period);
+ HistoryEntry historyEntry = buildHistory(repoId, period, now);
entitiesToSave.add(historyEntry);
ImmutableSet extends ImmutableObject> billsAndPolls = createBillingEventsAndPollMessages(
- domainName, application, historyEntry, isSunrushAddGracePeriod, registry, years);
+ domainName, application, historyEntry, isSunrushAddGracePeriod, registry, now, years);
entitiesToSave.addAll(billsAndPolls);
DateTime registrationExpirationTime = leapSafeAddYears(now, years);
DomainResource newDomain = new DomainResource.Builder()
@@ -173,21 +178,21 @@ public class DomainAllocateFlow extends Flow implements TransactionalFlow {
.build();
entitiesToSave.add(
newDomain,
- buildApplicationHistory(application),
+ buildApplicationHistory(application, now),
updateApplication(application),
ForeignKeyIndex.create(newDomain, newDomain.getDeletionTime()),
EppResourceIndex.create(Key.create(newDomain)));
// Anchor tenant registrations override LRP.
String authInfoToken = authInfo.getPw().getValue();
- if (hasLrpToken(domainName, registry, authInfoToken)) {
+ if (hasLrpToken(domainName, registry, authInfoToken, now)) {
entitiesToSave.add(prepareMarkedLrpTokenEntity(authInfoToken, domainName, historyEntry));
}
ofy().save().entities(entitiesToSave.build());
enqueueTasks(allocateCreate, newDomain);
- return createOutput(
- Result.Code.SUCCESS,
- DomainCreateData.create(targetId, now, registrationExpirationTime),
- createResponseExtensions(registry, years));
+ return responseBuilder
+ .setResData(DomainCreateData.create(targetId, now, registrationExpirationTime))
+ .setExtensions(createResponseExtensions(now, registry, years))
+ .build();
}
private T getOnly(
@@ -201,7 +206,8 @@ public class DomainAllocateFlow extends Flow implements TransactionalFlow {
}
}
- private DomainApplication loadAndValidateApplication(String applicationRoid) throws EppException {
+ private DomainApplication loadAndValidateApplication(
+ String applicationRoid, DateTime now) throws EppException {
DomainApplication application = loadDomainApplication(applicationRoid, now);
if (application == null) {
throw new MissingApplicationException(applicationRoid);
@@ -212,7 +218,7 @@ public class DomainAllocateFlow extends Flow implements TransactionalFlow {
return application;
}
- private HistoryEntry buildHistory(String repoId, Period period) {
+ private HistoryEntry buildHistory(String repoId, Period period, DateTime now) {
return historyBuilder
.setType(HistoryEntry.Type.DOMAIN_ALLOCATE)
.setPeriod(period)
@@ -227,12 +233,13 @@ public class DomainAllocateFlow extends Flow implements TransactionalFlow {
HistoryEntry historyEntry,
boolean isSunrushAddGracePeriod,
Registry registry,
+ DateTime now,
int years) {
DateTime registrationExpirationTime = leapSafeAddYears(now, years);
BillingEvent.OneTime oneTimeBillingEvent = createOneTimeBillingEvent(
- application, historyEntry, isSunrushAddGracePeriod, registry, years);
+ application, historyEntry, isSunrushAddGracePeriod, registry, now, years);
PollMessage.OneTime oneTimePollMessage =
- createOneTimePollMessage(application, historyEntry, getReservationType(domainName));
+ createOneTimePollMessage(application, historyEntry, getReservationType(domainName), now);
// Create a new autorenew billing event and poll message starting at the expiration time.
BillingEvent.Recurring autorenewBillingEvent =
createAutorenewBillingEvent(historyEntry, registrationExpirationTime);
@@ -250,6 +257,7 @@ public class DomainAllocateFlow extends Flow implements TransactionalFlow {
HistoryEntry historyEntry,
boolean isSunrushAddGracePeriod,
Registry registry,
+ DateTime now,
int years) {
return new BillingEvent.OneTime.Builder()
.setReason(Reason.CREATE)
@@ -296,7 +304,7 @@ public class DomainAllocateFlow extends Flow implements TransactionalFlow {
.build();
}
- private GracePeriod createGracePeriod(boolean isSunrushAddGracePeriod,
+ private static GracePeriod createGracePeriod(boolean isSunrushAddGracePeriod,
BillingEvent.OneTime oneTimeBillingEvent) {
return GracePeriod.forBillingEvent(
isSunrushAddGracePeriod ? GracePeriodStatus.SUNRUSH_ADD : GracePeriodStatus.ADD,
@@ -304,7 +312,7 @@ public class DomainAllocateFlow extends Flow implements TransactionalFlow {
}
/** Create a history entry (with no xml or trid) to record that we updated the application. */
- private HistoryEntry buildApplicationHistory(DomainApplication application) {
+ private static HistoryEntry buildApplicationHistory(DomainApplication application, DateTime now) {
return new HistoryEntry.Builder()
.setType(HistoryEntry.Type.DOMAIN_APPLICATION_STATUS_UPDATE)
.setParent(application)
@@ -324,7 +332,10 @@ public class DomainAllocateFlow extends Flow implements TransactionalFlow {
/** Create a poll message informing the registrar that the application status was updated. */
private PollMessage.OneTime createOneTimePollMessage(
- DomainApplication application, HistoryEntry historyEntry, ReservationType reservationType) {
+ DomainApplication application,
+ HistoryEntry historyEntry,
+ ReservationType reservationType,
+ DateTime now) {
return new PollMessage.OneTime.Builder()
.setClientId(historyEntry.getClientId())
.setEventTime(now)
@@ -345,7 +356,7 @@ public class DomainAllocateFlow extends Flow implements TransactionalFlow {
}
private boolean hasLrpToken(
- InternetDomainName domainName, Registry registry, String authInfoToken) {
+ InternetDomainName domainName, Registry registry, String authInfoToken, DateTime now) {
return registry.getLrpPeriod().contains(now)
&& !matchesAnchorTenantReservation(domainName, authInfoToken);
}
@@ -360,7 +371,7 @@ public class DomainAllocateFlow extends Flow implements TransactionalFlow {
}
private ImmutableList createResponseExtensions(
- Registry registry, int years) throws EppException {
+ DateTime now, Registry registry, int years) throws EppException {
EppCommandOperations commandOperations = TldSpecificLogicProxy.getCreatePrice(
registry, targetId, clientId, now, years, eppInput);
FeeTransformCommandExtension feeCreate =
diff --git a/java/google/registry/flows/domain/DomainApplicationCreateFlow.java b/java/google/registry/flows/domain/DomainApplicationCreateFlow.java
index 716e5fa20..377f6053a 100644
--- a/java/google/registry/flows/domain/DomainApplicationCreateFlow.java
+++ b/java/google/registry/flows/domain/DomainApplicationCreateFlow.java
@@ -39,7 +39,6 @@ import static google.registry.flows.domain.DomainFlowUtils.verifySignedMarks;
import static google.registry.flows.domain.DomainFlowUtils.verifyUnitIsYears;
import static google.registry.model.EppResourceUtils.createDomainRoid;
import static google.registry.model.domain.fee.Fee.FEE_CREATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.index.DomainApplicationIndex.loadActiveApplicationsByDomainName;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.model.registry.label.ReservedList.matchesAnchorTenantReservation;
@@ -56,8 +55,8 @@ import google.registry.flows.EppException.CommandUseErrorException;
import google.registry.flows.EppException.ObjectAlreadyExistsException;
import google.registry.flows.EppException.RequiredParameterMissingException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
+import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.domain.TldSpecificLogicProxy.EppCommandOperations;
@@ -76,9 +75,11 @@ import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.domain.secdns.SecDnsCreateExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppcommon.StatusValue;
+import google.registry.model.eppcommon.Trid;
+import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppoutput.CreateData.DomainCreateData;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
import google.registry.model.index.DomainApplicationIndex;
import google.registry.model.index.EppResourceIndex;
@@ -89,6 +90,7 @@ import google.registry.model.reporting.HistoryEntry;
import google.registry.model.smd.AbstractSignedMark;
import google.registry.model.smd.EncodedSignedMark;
import javax.inject.Inject;
+import org.joda.time.DateTime;
/**
* An EPP flow that creates a new application for a domain resource.
@@ -153,18 +155,22 @@ import javax.inject.Inject;
* @error {@link DomainFlowUtils.UnsupportedFeeAttributeException}
* @error {@link DomainFlowUtils.UnsupportedMarkTypeException}
*/
-public final class DomainApplicationCreateFlow extends Flow implements TransactionalFlow {
+public final class DomainApplicationCreateFlow implements TransactionalFlow {
@Inject ExtensionManager extensionManager;
+ @Inject EppInput eppInput;
@Inject AuthInfo authInfo;
@Inject ResourceCommand resourceCommand;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
+ @Inject @Superuser boolean isSuperuser;
@Inject HistoryEntry.Builder historyBuilder;
+ @Inject Trid trid;
+ @Inject EppResponse.Builder responseBuilder;
@Inject DomainApplicationCreateFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(
SecDnsCreateExtension.class,
FlagsCreateCommandExtension.class,
@@ -173,6 +179,7 @@ public final class DomainApplicationCreateFlow extends Flow implements Transacti
extensionManager.registerAsGroup(FEE_CREATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
+ DateTime now = ofy().getTransactionTime();
Create command = cloneAndLinkReferences((Create) resourceCommand, now);
failfastForCreate(targetId, now);
// Fail if the domain is already registered (e.g. this is a landrush application but the domain
@@ -193,13 +200,13 @@ public final class DomainApplicationCreateFlow extends Flow implements Transacti
validateCreateCommandContactsAndNameservers(command, tld);
LaunchCreateExtension launchCreate = eppInput.getSingleExtension(LaunchCreateExtension.class);
if (launchCreate != null) {
- validateLaunchCreateExtension(launchCreate, registry, domainName);
+ validateLaunchCreateExtension(launchCreate, registry, domainName, now);
}
boolean isAnchorTenant =
matchesAnchorTenantReservation(domainName, authInfo.getPw().getValue());
if (!isSuperuser) {
verifyPremiumNameIsNotBlocked(targetId, now, clientId);
- prohibitLandrushIfExactlyOneSunrise(registry);
+ prohibitLandrushIfExactlyOneSunrise(registry, now);
if (!isAnchorTenant) {
boolean isSunriseApplication = !launchCreate.getSignedMarks().isEmpty();
verifyNotReserved(domainName, isSunriseApplication);
@@ -236,7 +243,7 @@ public final class DomainApplicationCreateFlow extends Flow implements Transacti
}})
.toList())
.build();
- HistoryEntry historyEntry = buildHistory(newApplication.getRepoId(), command.getPeriod());
+ HistoryEntry historyEntry = buildHistory(newApplication.getRepoId(), command.getPeriod(), now);
ImmutableSet.Builder entitiesToSave = new ImmutableSet.Builder<>();
handleExtraFlowLogic(
registry.getTldStr(), command.getPeriod().getValue(), historyEntry, newApplication);
@@ -252,16 +259,18 @@ public final class DomainApplicationCreateFlow extends Flow implements Transacti
prepareMarkedLrpTokenEntity(authInfo.getPw().getValue(), domainName, historyEntry));
}
ofy().save().entities(entitiesToSave.build());
- return createOutput(
- SUCCESS,
- DomainCreateData.create(targetId, now, null),
- createResponseExtensions(
- newApplication.getForeignKey(), launchCreate.getPhase(), feeCreate, commandOperations));
+ return responseBuilder
+ .setResData(DomainCreateData.create(targetId, now, null))
+ .setExtensions(createResponseExtensions(
+ newApplication.getForeignKey(), launchCreate.getPhase(), feeCreate, commandOperations))
+ .build();
}
private void validateLaunchCreateExtension(
- LaunchCreateExtension launchCreate, Registry registry, InternetDomainName domainName)
- throws EppException {
+ LaunchCreateExtension launchCreate,
+ Registry registry,
+ InternetDomainName domainName,
+ DateTime now) throws EppException {
verifyNoCodeMarks(launchCreate);
boolean hasClaimsNotice = launchCreate.getNotice() != null;
if (hasClaimsNotice) {
@@ -302,7 +311,7 @@ public final class DomainApplicationCreateFlow extends Flow implements Transacti
* Prohibit creating a landrush application in LANDRUSH (but not in SUNRUSH) if there is exactly
* one sunrise application for the same name.
*/
- private void prohibitLandrushIfExactlyOneSunrise(Registry registry)
+ private void prohibitLandrushIfExactlyOneSunrise(Registry registry, DateTime now)
throws UncontestedSunriseApplicationBlockedInLandrushException {
if (registry.getTldState(now) == TldState.LANDRUSH) {
ImmutableSet applications =
@@ -314,7 +323,7 @@ public final class DomainApplicationCreateFlow extends Flow implements Transacti
}
}
- private HistoryEntry buildHistory(String repoId, Period period) {
+ private HistoryEntry buildHistory(String repoId, Period period, DateTime now) {
return historyBuilder
.setType(HistoryEntry.Type.DOMAIN_APPLICATION_CREATE)
.setPeriod(period)
@@ -349,7 +358,7 @@ public final class DomainApplicationCreateFlow extends Flow implements Transacti
extraFlowLogic.get().performAdditionalApplicationCreateLogic(
newApplication,
clientId,
- now,
+ newApplication.getCreationTime(),
years,
eppInput,
historyEntry);
diff --git a/java/google/registry/flows/domain/DomainApplicationDeleteFlow.java b/java/google/registry/flows/domain/DomainApplicationDeleteFlow.java
index 6bb5949ef..bfdeca4d9 100644
--- a/java/google/registry/flows/domain/DomainApplicationDeleteFlow.java
+++ b/java/google/registry/flows/domain/DomainApplicationDeleteFlow.java
@@ -26,7 +26,6 @@ import static google.registry.flows.domain.DomainFlowUtils.verifyApplicationDoma
import static google.registry.flows.domain.DomainFlowUtils.verifyLaunchPhaseMatchesRegistryPhase;
import static google.registry.flows.domain.DomainFlowUtils.verifyRegistryStateAllowsLaunchFlows;
import static google.registry.model.EppResourceUtils.loadDomainApplication;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.ofy.ObjectifyService.ofy;
import com.google.common.base.Optional;
@@ -34,9 +33,9 @@ import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
import google.registry.flows.EppException.StatusProhibitsOperationException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ApplicationId;
import google.registry.flows.FlowModule.ClientId;
+import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.model.domain.DomainApplication;
@@ -44,11 +43,13 @@ import google.registry.model.domain.launch.LaunchDeleteExtension;
import google.registry.model.domain.launch.LaunchPhase;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppcommon.AuthInfo;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppinput.EppInput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.registry.Registry;
import google.registry.model.registry.Registry.TldState;
import google.registry.model.reporting.HistoryEntry;
import javax.inject.Inject;
+import org.joda.time.DateTime;
/**
* An EPP flow that deletes a domain application.
@@ -62,21 +63,25 @@ import javax.inject.Inject;
* @error {@link DomainFlowUtils.LaunchPhaseMismatchException}
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
*/
-public final class DomainApplicationDeleteFlow extends Flow implements TransactionalFlow {
+public final class DomainApplicationDeleteFlow implements TransactionalFlow {
@Inject ExtensionManager extensionManager;
+ @Inject EppInput eppInput;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject @ApplicationId String applicationId;
+ @Inject @Superuser boolean isSuperuser;
@Inject HistoryEntry.Builder historyBuilder;
+ @Inject EppResponse.Builder responseBuilder;
@Inject DomainApplicationDeleteFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(MetadataExtension.class, LaunchDeleteExtension.class);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
+ DateTime now = ofy().getTransactionTime();
DomainApplication existingApplication = verifyExistence(
DomainApplication.class, applicationId, loadDomainApplication(applicationId, now));
verifyApplicationDomainMatchesTargetId(existingApplication, targetId);
@@ -105,7 +110,7 @@ public final class DomainApplicationDeleteFlow extends Flow implements Transacti
updateForeignKeyIndexDeletionTime(newApplication);
handlePendingTransferOnDelete(existingApplication, newApplication, now, historyEntry);
ofy().save().entities(newApplication, historyEntry);
- return createOutput(SUCCESS);
+ return responseBuilder.build();
}
/** A sunrise application cannot be deleted during landrush. */
diff --git a/java/google/registry/flows/domain/DomainApplicationInfoFlow.java b/java/google/registry/flows/domain/DomainApplicationInfoFlow.java
index 79601f601..ca2f9506c 100644
--- a/java/google/registry/flows/domain/DomainApplicationInfoFlow.java
+++ b/java/google/registry/flows/domain/DomainApplicationInfoFlow.java
@@ -22,7 +22,6 @@ import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
import static google.registry.flows.domain.DomainFlowUtils.addSecDnsExtensionIfPresent;
import static google.registry.flows.domain.DomainFlowUtils.verifyApplicationDomainMatchesTargetId;
import static google.registry.model.EppResourceUtils.loadDomainApplication;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
@@ -39,12 +38,14 @@ import google.registry.model.domain.DomainCommand.Info;
import google.registry.model.domain.launch.LaunchInfoExtension;
import google.registry.model.domain.launch.LaunchInfoResponseExtension;
import google.registry.model.eppcommon.AuthInfo;
+import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.ResourceCommand;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
import google.registry.model.mark.Mark;
import google.registry.model.smd.EncodedSignedMark;
import google.registry.model.smd.SignedMark;
+import google.registry.util.Clock;
import javax.inject.Inject;
/**
@@ -59,18 +60,21 @@ import javax.inject.Inject;
* @error {@link DomainApplicationInfoFlow.ApplicationLaunchPhaseMismatchException}
* @error {@link MissingApplicationIdException}
*/
-public final class DomainApplicationInfoFlow extends Flow {
+public final class DomainApplicationInfoFlow implements Flow {
@Inject ResourceCommand resourceCommand;
@Inject ExtensionManager extensionManager;
+ @Inject EppInput eppInput;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject @ApplicationId String applicationId;
+ @Inject Clock clock;
+ @Inject EppResponse.Builder responseBuilder;
@Inject DomainApplicationInfoFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(LaunchInfoExtension.class);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
@@ -78,7 +82,9 @@ public final class DomainApplicationInfoFlow extends Flow {
throw new MissingApplicationIdException();
}
DomainApplication application = verifyExistence(
- DomainApplication.class, applicationId, loadDomainApplication(applicationId, now));
+ DomainApplication.class,
+ applicationId,
+ loadDomainApplication(applicationId, clock.nowUtc()));
verifyApplicationDomainMatchesTargetId(application, targetId);
verifyOptionalAuthInfoForResource(authInfo, application);
LaunchInfoExtension launchInfo = eppInput.getSingleExtension(LaunchInfoExtension.class);
@@ -87,10 +93,10 @@ public final class DomainApplicationInfoFlow extends Flow {
}
// We don't support authInfo for applications, so if it's another registrar always fail.
verifyResourceOwnership(clientId, application);
- return createOutput(
- SUCCESS,
- getResourceInfo(application),
- getDomainResponseExtensions(application, launchInfo));
+ return responseBuilder
+ .setResData(getResourceInfo(application))
+ .setExtensions(getDomainResponseExtensions(application, launchInfo))
+ .build();
}
DomainApplication getResourceInfo(DomainApplication application) {
diff --git a/java/google/registry/flows/domain/DomainApplicationUpdateFlow.java b/java/google/registry/flows/domain/DomainApplicationUpdateFlow.java
index 2d5d6a05d..d7349bd7c 100644
--- a/java/google/registry/flows/domain/DomainApplicationUpdateFlow.java
+++ b/java/google/registry/flows/domain/DomainApplicationUpdateFlow.java
@@ -40,7 +40,6 @@ import static google.registry.flows.domain.DomainFlowUtils.verifyClientUpdateNot
import static google.registry.flows.domain.DomainFlowUtils.verifyNotInPendingDelete;
import static google.registry.model.EppResourceUtils.loadDomainApplication;
import static google.registry.model.domain.fee.Fee.FEE_UPDATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.ofy.ObjectifyService.ofy;
import com.google.common.base.Optional;
@@ -50,9 +49,9 @@ import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
import google.registry.flows.EppException.StatusProhibitsOperationException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ApplicationId;
import google.registry.flows.FlowModule.ClientId;
+import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.model.ImmutableObject;
@@ -66,10 +65,12 @@ import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.domain.secdns.SecDnsUpdateExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppcommon.StatusValue;
+import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.ResourceCommand;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.reporting.HistoryEntry;
import javax.inject.Inject;
+import org.joda.time.DateTime;
/**
* An EPP flow that updates a domain application.
@@ -101,7 +102,7 @@ import javax.inject.Inject;
* @error {@link DomainFlowUtils.UrgentAttributeNotSupportedException}
* @error {@link DomainApplicationUpdateFlow.ApplicationStatusProhibitsUpdateException}
*/
-public class DomainApplicationUpdateFlow extends Flow implements TransactionalFlow {
+public class DomainApplicationUpdateFlow implements TransactionalFlow {
/**
* Note that CLIENT_UPDATE_PROHIBITED is intentionally not in this list. This is because it
@@ -121,15 +122,18 @@ public class DomainApplicationUpdateFlow extends Flow implements TransactionalFl
@Inject ResourceCommand resourceCommand;
@Inject ExtensionManager extensionManager;
+ @Inject EppInput eppInput;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject @ApplicationId String applicationId;
+ @Inject @Superuser boolean isSuperuser;
@Inject HistoryEntry.Builder historyBuilder;
+ @Inject EppResponse.Builder responseBuilder;
@Inject DomainApplicationUpdateFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(
LaunchUpdateExtension.class,
MetadataExtension.class,
@@ -137,6 +141,7 @@ public class DomainApplicationUpdateFlow extends Flow implements TransactionalFl
extensionManager.registerAsGroup(FEE_UPDATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
+ DateTime now = ofy().getTransactionTime();
Update command = cloneAndLinkReferences((Update) resourceCommand, now);
DomainApplication existingApplication = verifyExistence(
DomainApplication.class, applicationId, loadDomainApplication(applicationId, now));
@@ -144,11 +149,11 @@ public class DomainApplicationUpdateFlow extends Flow implements TransactionalFl
verifyNoDisallowedStatuses(existingApplication, UPDATE_DISALLOWED_STATUSES);
verifyOptionalAuthInfoForResource(authInfo, existingApplication);
verifyUpdateAllowed(existingApplication, command);
- HistoryEntry historyEntry = buildHistory(existingApplication);
- DomainApplication newApplication = updateApplication(existingApplication, command);
+ HistoryEntry historyEntry = buildHistory(existingApplication, now);
+ DomainApplication newApplication = updateApplication(existingApplication, command, now);
validateNewApplication(newApplication);
ofy().save().entities(newApplication, historyEntry);
- return createOutput(SUCCESS);
+ return responseBuilder.build();
}
protected final void verifyUpdateAllowed(
@@ -178,7 +183,7 @@ public class DomainApplicationUpdateFlow extends Flow implements TransactionalFl
tld, add.getNameserverFullyQualifiedHostNames());
}
- private HistoryEntry buildHistory(DomainApplication existingApplication) {
+ private HistoryEntry buildHistory(DomainApplication existingApplication, DateTime now) {
return historyBuilder
.setType(HistoryEntry.Type.DOMAIN_APPLICATION_UPDATE)
.setModificationTime(now)
@@ -187,7 +192,7 @@ public class DomainApplicationUpdateFlow extends Flow implements TransactionalFl
}
private DomainApplication updateApplication(
- DomainApplication application, Update command) throws EppException {
+ DomainApplication application, Update command, DateTime now) throws EppException {
AddRemove add = command.getInnerAdd();
AddRemove remove = command.getInnerRemove();
checkSameValuesNotAddedAndRemoved(add.getNameservers(), remove.getNameservers());
diff --git a/java/google/registry/flows/domain/DomainCheckFlow.java b/java/google/registry/flows/domain/DomainCheckFlow.java
index d8909eb7a..062c7a333 100644
--- a/java/google/registry/flows/domain/DomainCheckFlow.java
+++ b/java/google/registry/flows/domain/DomainCheckFlow.java
@@ -24,12 +24,9 @@ import static google.registry.flows.domain.DomainFlowUtils.validateDomainNameWit
import static google.registry.flows.domain.DomainFlowUtils.verifyNotInPredelegation;
import static google.registry.model.EppResourceUtils.checkResourcesExist;
import static google.registry.model.domain.fee.Fee.FEE_CHECK_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER;
-import static google.registry.model.domain.fee.Fee.FEE_EXTENSION_URIS;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.index.DomainApplicationIndex.loadActiveApplicationsByDomainName;
import static google.registry.model.registry.label.ReservationType.UNRESERVED;
import static google.registry.pricing.PricingEngineProxy.isDomainPremium;
-import static google.registry.util.CollectionUtils.nullToEmpty;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
@@ -44,6 +41,7 @@ import google.registry.flows.EppException.ParameterValuePolicyErrorException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
+import google.registry.flows.FlowModule.Superuser;
import google.registry.model.domain.DomainApplication;
import google.registry.model.domain.DomainCommand.Check;
import google.registry.model.domain.DomainResource;
@@ -51,19 +49,21 @@ import google.registry.model.domain.fee.FeeCheckCommandExtension;
import google.registry.model.domain.fee.FeeCheckCommandExtensionItem;
import google.registry.model.domain.fee.FeeCheckResponseExtensionItem;
import google.registry.model.domain.launch.LaunchCheckExtension;
+import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppoutput.CheckData.DomainCheck;
import google.registry.model.eppoutput.CheckData.DomainCheckData;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
import google.registry.model.registry.Registry;
import google.registry.model.registry.Registry.TldState;
import google.registry.model.registry.label.ReservationType;
-import java.util.Collections;
+import google.registry.util.Clock;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
+import org.joda.time.DateTime;
/**
* An EPP flow that checks whether a domain can be provisioned.
@@ -90,7 +90,7 @@ import javax.inject.Inject;
* @error {@link DomainFlowUtils.UnknownFeeCommandException}
* @error {@link OnlyCheckedNamesCanBeFeeCheckedException}
*/
-public final class DomainCheckFlow extends Flow {
+public final class DomainCheckFlow implements Flow {
/**
* The TLD states during which we want to report a domain with pending applications as
@@ -101,18 +101,23 @@ public final class DomainCheckFlow extends Flow {
@Inject ResourceCommand resourceCommand;
@Inject ExtensionManager extensionManager;
+ @Inject EppInput eppInput;
@Inject @ClientId String clientId;
@Inject @Config("maxChecks") int maxChecks;
+ @Inject @Superuser boolean isSuperuser;
+ @Inject Clock clock;
+ @Inject EppResponse.Builder responseBuilder;
@Inject DomainCheckFlow() {}
@Override
- public EppOutput run() throws EppException {
+ public EppResponse run() throws EppException {
extensionManager.register(LaunchCheckExtension.class);
extensionManager.registerAsGroup(FEE_CHECK_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
List targetIds = ((Check) resourceCommand).getTargetIds();
verifyTargetIdCount(targetIds, maxChecks);
+ DateTime now = clock.nowUtc();
ImmutableMap.Builder domains = new ImmutableMap.Builder<>();
// Only check that the registrar has access to a TLD the first time it is encountered
Set seenTlds = new HashSet<>();
@@ -133,17 +138,17 @@ public final class DomainCheckFlow extends Flow {
Set existingIds = checkResourcesExist(DomainResource.class, targetIds, now);
ImmutableList.Builder checks = new ImmutableList.Builder<>();
for (String targetId : targetIds) {
- String message = getMessageForCheck(domainNames.get(targetId), existingIds);
+ String message = getMessageForCheck(domainNames.get(targetId), existingIds, now);
checks.add(DomainCheck.create(message == null, targetId, message));
}
- return createOutput(
- SUCCESS,
- DomainCheckData.create(checks.build()),
- getResponseExtensions(domainNames));
+ return responseBuilder
+ .setResData(DomainCheckData.create(checks.build()))
+ .setExtensions(getResponseExtensions(domainNames, now))
+ .build();
}
private String getMessageForCheck(
- InternetDomainName domainName, Set existingIds) {
+ InternetDomainName domainName, Set existingIds, DateTime now) {
if (existingIds.contains(domainName.toString())) {
return "In use";
}
@@ -161,9 +166,7 @@ public final class DomainCheckFlow extends Flow {
if (reservationType == UNRESERVED
&& isDomainPremium(domainName.toString(), now)
&& registry.getPremiumPriceAckRequired()
- && Collections.disjoint(
- nullToEmpty(sessionMetadata.getServiceExtensionUris()),
- FEE_EXTENSION_URIS)) {
+ && eppInput.getSingleExtension(FeeCheckCommandExtension.class) == null) {
return "Premium names require EPP ext.";
}
return reservationType.getMessageForCheck();
@@ -172,7 +175,7 @@ public final class DomainCheckFlow extends Flow {
/** Handle the fee check extension. */
private ImmutableList extends ResponseExtension> getResponseExtensions(
- ImmutableMap domainNames) throws EppException {
+ ImmutableMap domainNames, DateTime now) throws EppException {
FeeCheckCommandExtension, ?> feeCheck =
eppInput.getFirstExtensionOfClasses(FEE_CHECK_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
if (feeCheck == null) {
diff --git a/java/google/registry/flows/domain/DomainCreateFlow.java b/java/google/registry/flows/domain/DomainCreateFlow.java
index 812deaac3..78bd80a9e 100644
--- a/java/google/registry/flows/domain/DomainCreateFlow.java
+++ b/java/google/registry/flows/domain/DomainCreateFlow.java
@@ -54,8 +54,8 @@ import google.registry.flows.EppException;
import google.registry.flows.EppException.CommandUseErrorException;
import google.registry.flows.EppException.StatusProhibitsOperationException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
+import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.domain.TldSpecificLogicProxy.EppCommandOperations;
@@ -78,10 +78,10 @@ import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.secdns.SecDnsCreateExtension;
import google.registry.model.eppcommon.AuthInfo;
+import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppoutput.CreateData.DomainCreateData;
-import google.registry.model.eppoutput.EppOutput;
-import google.registry.model.eppoutput.Result;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.index.EppResourceIndex;
import google.registry.model.index.ForeignKeyIndex;
import google.registry.model.ofy.ObjectifyService;
@@ -149,21 +149,24 @@ import org.joda.time.DateTime;
* @error {@link DomainCreateFlow.NoGeneralRegistrationsInCurrentPhaseException}
*/
-public class DomainCreateFlow extends Flow implements TransactionalFlow {
+public class DomainCreateFlow implements TransactionalFlow {
private static final Set QLP_SMD_ALLOWED_STATES =
Sets.immutableEnumSet(TldState.SUNRISE, TldState.SUNRUSH);
@Inject ExtensionManager extensionManager;
+ @Inject EppInput eppInput;
@Inject AuthInfo authInfo;
@Inject ResourceCommand resourceCommand;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
+ @Inject @Superuser boolean isSuperuser;
@Inject HistoryEntry.Builder historyBuilder;
+ @Inject EppResponse.Builder responseBuilder;
@Inject DomainCreateFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(
SecDnsCreateExtension.class,
FlagsCreateCommandExtension.class,
@@ -172,6 +175,7 @@ public class DomainCreateFlow extends Flow implements TransactionalFlow {
extensionManager.registerAsGroup(FEE_CREATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
+ DateTime now = ofy().getTransactionTime();
Create command = cloneAndLinkReferences((Create) resourceCommand, now);
Period period = command.getPeriod();
verifyUnitIsYears(period);
@@ -219,17 +223,17 @@ public class DomainCreateFlow extends Flow implements TransactionalFlow {
verifyClaimsNoticeIfAndOnlyIfNeeded(domainName, hasSignedMarks, hasClaimsNotice);
}
verifyPremiumNameIsNotBlocked(targetId, now, clientId);
- verifyNoOpenApplications();
+ verifyNoOpenApplications(now);
verifyIsGaOrIsSpecialCase(tldState, isAnchorTenant);
}
SecDnsCreateExtension secDnsCreate =
validateSecDnsExtension(eppInput.getSingleExtension(SecDnsCreateExtension.class));
String repoId = createDomainRoid(ObjectifyService.allocateId(), registry.getTldStr());
DateTime registrationExpirationTime = leapSafeAddYears(now, years);
- HistoryEntry historyEntry = buildHistory(repoId, period);
+ HistoryEntry historyEntry = buildHistory(repoId, period, now);
// Bill for the create.
- BillingEvent.OneTime createBillingEvent =
- createOneTimeBillingEvent(registry, isAnchorTenant, years, commandOperations, historyEntry);
+ BillingEvent.OneTime createBillingEvent = createOneTimeBillingEvent(
+ registry, isAnchorTenant, years, commandOperations, historyEntry, now);
// Create a new autorenew billing event and poll message starting at the expiration time.
BillingEvent.Recurring autorenewBillingEvent =
createAutorenewBillingEvent(historyEntry, registrationExpirationTime);
@@ -266,24 +270,24 @@ public class DomainCreateFlow extends Flow implements TransactionalFlow {
.setContacts(command.getContacts())
.addGracePeriod(GracePeriod.forBillingEvent(GracePeriodStatus.ADD, createBillingEvent))
.build();
- handleExtraFlowLogic(registry.getTldStr(), years, historyEntry, newDomain);
+ handleExtraFlowLogic(registry.getTldStr(), years, historyEntry, newDomain, now);
entitiesToSave.add(
newDomain,
ForeignKeyIndex.create(newDomain, newDomain.getDeletionTime()),
EppResourceIndex.create(Key.create(newDomain)));
-
+
// Anchor tenant registrations override LRP, and landrush applications can skip it.
// If a token is passed in outside of an LRP phase, it is simply ignored (i.e. never redeemed).
- if (isLrpCreate(registry, isAnchorTenant)) {
+ if (isLrpCreate(registry, isAnchorTenant, now)) {
entitiesToSave.add(
prepareMarkedLrpTokenEntity(authInfo.getPw().getValue(), domainName, historyEntry));
}
enqueueTasks(hasSignedMarks, hasClaimsNotice, newDomain);
ofy().save().entities(entitiesToSave.build());
- return createOutput(
- Result.Code.SUCCESS,
- DomainCreateData.create(targetId, now, registrationExpirationTime),
- createResponseExtensions(feeCreate, commandOperations));
+ return responseBuilder
+ .setResData(DomainCreateData.create(targetId, now, registrationExpirationTime))
+ .setExtensions(createResponseExtensions(feeCreate, commandOperations))
+ .build();
}
private boolean isAnchorTenant(InternetDomainName domainName) {
@@ -301,7 +305,7 @@ public class DomainCreateFlow extends Flow implements TransactionalFlow {
}
/** Prohibit creating a domain if there is an open application for the same name. */
- private void verifyNoOpenApplications() throws DomainHasOpenApplicationsException {
+ private void verifyNoOpenApplications(DateTime now) throws DomainHasOpenApplicationsException {
for (DomainApplication application : loadActiveApplicationsByDomainName(targetId, now)) {
if (!application.getApplicationStatus().isFinalStatus()) {
throw new DomainHasOpenApplicationsException();
@@ -317,7 +321,7 @@ public class DomainCreateFlow extends Flow implements TransactionalFlow {
}
}
- private HistoryEntry buildHistory(String repoId, Period period) {
+ private HistoryEntry buildHistory(String repoId, Period period, DateTime now) {
return historyBuilder
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setPeriod(period)
@@ -331,7 +335,8 @@ public class DomainCreateFlow extends Flow implements TransactionalFlow {
boolean isAnchorTenant,
int years,
EppCommandOperations commandOperations,
- HistoryEntry historyEntry) {
+ HistoryEntry historyEntry,
+ DateTime now) {
return new BillingEvent.OneTime.Builder()
.setReason(Reason.CREATE)
.setTargetId(targetId)
@@ -387,12 +392,12 @@ public class DomainCreateFlow extends Flow implements TransactionalFlow {
.build();
}
- private boolean isLrpCreate(Registry registry, boolean isAnchorTenant) {
+ private boolean isLrpCreate(Registry registry, boolean isAnchorTenant, DateTime now) {
return registry.getLrpPeriod().contains(now) && !isAnchorTenant;
}
private void handleExtraFlowLogic(
- String tld, int years, HistoryEntry historyEntry, DomainResource newDomain)
+ String tld, int years, HistoryEntry historyEntry, DomainResource newDomain, DateTime now)
throws EppException {
Optional extraFlowLogic =
RegistryExtraFlowLogicProxy.newInstanceForTld(tld);
diff --git a/java/google/registry/flows/domain/DomainDeleteFlow.java b/java/google/registry/flows/domain/DomainDeleteFlow.java
index 4f60ea191..6dee104e2 100644
--- a/java/google/registry/flows/domain/DomainDeleteFlow.java
+++ b/java/google/registry/flows/domain/DomainDeleteFlow.java
@@ -40,9 +40,10 @@ import google.registry.dns.DnsQueue;
import google.registry.flows.EppException;
import google.registry.flows.EppException.AssociationProhibitsOperationException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
+import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
+import google.registry.flows.SessionMetadata;
import google.registry.flows.TransactionalFlow;
import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingEvent;
@@ -61,7 +62,9 @@ import google.registry.model.domain.secdns.SecDnsCreateExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppcommon.ProtocolDefinition.ServiceExtension;
import google.registry.model.eppcommon.StatusValue;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppcommon.Trid;
+import google.registry.model.eppinput.EppInput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.poll.PendingActionNotificationResponse.DomainPendingActionNotificationResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.poll.PollMessage.OneTime;
@@ -84,7 +87,7 @@ import org.joda.time.DateTime;
* @error {@link DomainFlowUtils.BadCommandForRegistryPhaseException}
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
*/
-public final class DomainDeleteFlow extends Flow implements TransactionalFlow {
+public final class DomainDeleteFlow implements TransactionalFlow {
private static final ImmutableSet DISALLOWED_STATUSES = ImmutableSet.of(
StatusValue.LINKED,
@@ -93,23 +96,29 @@ public final class DomainDeleteFlow extends Flow implements TransactionalFlow {
StatusValue.SERVER_DELETE_PROHIBITED);
@Inject ExtensionManager extensionManager;
+ @Inject EppInput eppInput;
+ @Inject SessionMetadata sessionMetadata;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
+ @Inject @Superuser boolean isSuperuser;
@Inject HistoryEntry.Builder historyBuilder;
@Inject DnsQueue dnsQueue;
+ @Inject Trid trid;
+ @Inject EppResponse.Builder responseBuilder;
@Inject DomainDeleteFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(MetadataExtension.class, SecDnsCreateExtension.class);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
+ DateTime now = ofy().getTransactionTime();
// Loads the target resource if it exists
DomainResource existingDomain = loadAndVerifyExistence(DomainResource.class, targetId, now);
Registry registry = Registry.get(existingDomain.getTld());
- verifyDeleteAllowed(existingDomain, registry);
- HistoryEntry historyEntry = buildHistoryEntry(existingDomain);
+ verifyDeleteAllowed(existingDomain, registry, now);
+ HistoryEntry historyEntry = buildHistoryEntry(existingDomain, now);
Builder builder = (Builder) prepareDeletedResourceAsBuilder(existingDomain, now);
// If the domain is in the Add Grace Period, we delete it immediately, which is already
// reflected in the builder we just prepared. Otherwise we give it a PENDING_DELETE status.
@@ -131,7 +140,7 @@ public final class DomainDeleteFlow extends Flow implements TransactionalFlow {
clientId)))
.setDeletePollMessage(Key.create(deletePollMessage));
}
- handleExtraFlowLogic(existingDomain, historyEntry);
+ handleExtraFlowLogic(existingDomain, historyEntry, now);
DomainResource newDomain = builder.build();
updateForeignKeyIndexDeletionTime(newDomain);
handlePendingTransferOnDelete(existingDomain, newDomain, now, historyEntry);
@@ -150,13 +159,14 @@ public final class DomainDeleteFlow extends Flow implements TransactionalFlow {
}
}
ofy().save().entities(newDomain, historyEntry);
- return createOutput(
- newDomain.getDeletionTime().isAfter(now) ? SUCCESS_WITH_ACTION_PENDING : SUCCESS,
- null,
- getResponseExtensions(existingDomain));
+ return responseBuilder
+ .setResultFromCode(
+ newDomain.getDeletionTime().isAfter(now) ? SUCCESS_WITH_ACTION_PENDING : SUCCESS)
+ .setExtensions(getResponseExtensions(existingDomain, now))
+ .build();
}
- private void verifyDeleteAllowed(DomainResource existingDomain, Registry registry)
+ private void verifyDeleteAllowed(DomainResource existingDomain, Registry registry, DateTime now)
throws EppException {
verifyNoDisallowedStatuses(existingDomain, DISALLOWED_STATUSES);
verifyOptionalAuthInfoForResource(authInfo, existingDomain);
@@ -170,7 +180,7 @@ public final class DomainDeleteFlow extends Flow implements TransactionalFlow {
}
}
- private HistoryEntry buildHistoryEntry(DomainResource existingResource) {
+ private HistoryEntry buildHistoryEntry(DomainResource existingResource, DateTime now) {
return historyBuilder
.setType(HistoryEntry.Type.DOMAIN_DELETE)
.setModificationTime(now)
@@ -191,8 +201,9 @@ public final class DomainDeleteFlow extends Flow implements TransactionalFlow {
.build();
}
- private void handleExtraFlowLogic(DomainResource existingResource, HistoryEntry historyEntry)
- throws EppException {
+ private void handleExtraFlowLogic(
+ DomainResource existingResource, HistoryEntry historyEntry, DateTime now)
+ throws EppException {
Optional extraFlowLogic =
RegistryExtraFlowLogicProxy.newInstanceForDomain(existingResource);
if (extraFlowLogic.isPresent()) {
@@ -203,7 +214,7 @@ public final class DomainDeleteFlow extends Flow implements TransactionalFlow {
@Nullable
private ImmutableList getResponseExtensions(
- DomainResource existingDomain) {
+ DomainResource existingDomain, DateTime now) {
FeeTransformResponseExtension.Builder feeResponseBuilder = getDeleteResponseBuilder();
if (feeResponseBuilder == null) {
return null;
@@ -211,7 +222,7 @@ public final class DomainDeleteFlow extends Flow implements TransactionalFlow {
ImmutableList.Builder creditsBuilder = new ImmutableList.Builder<>();
for (GracePeriod gracePeriod : existingDomain.getGracePeriods()) {
if (gracePeriod.hasBillingEvent()) {
- Money cost = getGracePeriodCost(gracePeriod);
+ Money cost = getGracePeriodCost(gracePeriod, now);
creditsBuilder.add(Credit.create(
cost.negated().getAmount(), FeeType.CREDIT, gracePeriod.getType().getXmlName()));
feeResponseBuilder.setCurrency(checkNotNull(cost.getCurrencyUnit()));
@@ -224,7 +235,7 @@ public final class DomainDeleteFlow extends Flow implements TransactionalFlow {
return ImmutableList.of(feeResponseBuilder.setCredits(credits).build());
}
- private Money getGracePeriodCost(GracePeriod gracePeriod) {
+ private Money getGracePeriodCost(GracePeriod gracePeriod, DateTime now) {
if (gracePeriod.getType() == GracePeriodStatus.AUTO_RENEW) {
DateTime autoRenewTime =
ofy().load().key(checkNotNull(gracePeriod.getRecurringBillingEvent())).now()
diff --git a/java/google/registry/flows/domain/DomainInfoFlow.java b/java/google/registry/flows/domain/DomainInfoFlow.java
index f04b6b6b5..a2493e5c1 100644
--- a/java/google/registry/flows/domain/DomainInfoFlow.java
+++ b/java/google/registry/flows/domain/DomainInfoFlow.java
@@ -19,7 +19,6 @@ import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
import static google.registry.flows.domain.DomainFlowUtils.addSecDnsExtensionIfPresent;
import static google.registry.flows.domain.DomainFlowUtils.handleFeeRequest;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.util.CollectionUtils.forceEmptyToNull;
import com.google.common.base.Optional;
@@ -41,11 +40,14 @@ import google.registry.model.domain.flags.FlagsInfoResponseExtension;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.rgp.RgpInfoExtension;
import google.registry.model.eppcommon.AuthInfo;
+import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.ResourceCommand;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
+import google.registry.util.Clock;
import java.util.Set;
import javax.inject.Inject;
+import org.joda.time.DateTime;
/**
* An EPP flow that returns information about a domain.
@@ -61,26 +63,30 @@ import javax.inject.Inject;
* @error {@link DomainFlowUtils.FeeChecksDontSupportPhasesException}
* @error {@link DomainFlowUtils.RestoresAreAlwaysForOneYearException}
*/
-public final class DomainInfoFlow extends Flow {
+public final class DomainInfoFlow implements Flow {
@Inject ExtensionManager extensionManager;
+ @Inject ResourceCommand resourceCommand;
+ @Inject EppInput eppInput;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
- @Inject ResourceCommand resourceCommand;
+ @Inject Clock clock;
+ @Inject EppResponse.Builder responseBuilder;
@Inject DomainInfoFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(FeeInfoCommandExtensionV06.class);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
+ DateTime now = clock.nowUtc();
DomainResource domain = loadAndVerifyExistence(DomainResource.class, targetId, now);
verifyOptionalAuthInfoForResource(authInfo, domain);
- return createOutput(
- SUCCESS,
- getResourceInfo(domain),
- getDomainResponseExtensions(domain));
+ return responseBuilder
+ .setResData(getResourceInfo(domain))
+ .setExtensions(getDomainResponseExtensions(domain, now))
+ .build();
}
private DomainResource getResourceInfo(DomainResource domain) {
@@ -111,8 +117,8 @@ public final class DomainInfoFlow extends Flow {
return info.build();
}
- private ImmutableList getDomainResponseExtensions(DomainResource domain)
- throws EppException {
+ private ImmutableList getDomainResponseExtensions(
+ DomainResource domain, DateTime now) throws EppException {
ImmutableList.Builder extensions = new ImmutableList.Builder<>();
addSecDnsExtensionIfPresent(extensions, domain.getDsData());
ImmutableSet gracePeriodStatuses = domain.getGracePeriodStatuses();
diff --git a/java/google/registry/flows/domain/DomainRenewFlow.java b/java/google/registry/flows/domain/DomainRenewFlow.java
index 79496ec5b..a83ae8a82 100644
--- a/java/google/registry/flows/domain/DomainRenewFlow.java
+++ b/java/google/registry/flows/domain/DomainRenewFlow.java
@@ -28,7 +28,6 @@ import static google.registry.flows.domain.DomainFlowUtils.verifyUnitIsYears;
import static google.registry.model.domain.DomainResource.MAX_REGISTRATION_YEARS;
import static google.registry.model.domain.DomainResource.extendRegistrationWithCap;
import static google.registry.model.domain.fee.Fee.FEE_RENEW_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.util.DateTimeUtils.leapSafeAddYears;
@@ -40,8 +39,8 @@ import google.registry.flows.EppException;
import google.registry.flows.EppException.ObjectPendingTransferException;
import google.registry.flows.EppException.ParameterValueRangeErrorException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
+import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.domain.TldSpecificLogicProxy.EppCommandOperations;
@@ -60,8 +59,9 @@ import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppcommon.StatusValue;
+import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.ResourceCommand;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.registry.Registry;
import google.registry.model.reporting.HistoryEntry;
@@ -97,7 +97,7 @@ import org.joda.time.DateTime;
* @error {@link DomainRenewFlow.ExceedsMaxRegistrationYearsException}
* @error {@link DomainRenewFlow.IncorrectCurrentExpirationDateException}
*/
-public final class DomainRenewFlow extends Flow implements TransactionalFlow {
+public final class DomainRenewFlow implements TransactionalFlow {
private static final ImmutableSet RENEW_DISALLOWED_STATUSES = ImmutableSet.of(
StatusValue.CLIENT_RENEW_PROHIBITED,
@@ -106,18 +106,22 @@ public final class DomainRenewFlow extends Flow implements TransactionalFlow {
@Inject ResourceCommand resourceCommand;
@Inject ExtensionManager extensionManager;
+ @Inject EppInput eppInput;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
+ @Inject @Superuser boolean isSuperuser;
@Inject HistoryEntry.Builder historyBuilder;
+ @Inject EppResponse.Builder responseBuilder;
@Inject DomainRenewFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(MetadataExtension.class);
extensionManager.registerAsGroup(FEE_RENEW_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
+ DateTime now = ofy().getTransactionTime();
Renew command = (Renew) resourceCommand;
// Loads the target resource if it exists
DomainResource existingDomain = loadAndVerifyExistence(DomainResource.class, targetId, now);
@@ -143,7 +147,7 @@ public final class DomainRenewFlow extends Flow implements TransactionalFlow {
String tld = existingDomain.getTld();
// Bill for this explicit renew itself.
BillingEvent.OneTime explicitRenewEvent =
- createRenewBillingEvent(tld, commandOperations.getTotalCost(), years, historyEntry);
+ createRenewBillingEvent(tld, commandOperations.getTotalCost(), years, historyEntry, now);
// Create a new autorenew billing event and poll message starting at the new expiration time.
BillingEvent.Recurring newAutorenewEvent = newAutorenewBillingEvent(existingDomain)
.setEventTime(newExpirationTime)
@@ -170,10 +174,10 @@ public final class DomainRenewFlow extends Flow implements TransactionalFlow {
.build();
ofy().save().entities(
newDomain, historyEntry, explicitRenewEvent, newAutorenewEvent, newAutorenewPollMessage);
- return createOutput(
- SUCCESS,
- DomainRenewData.create(targetId, newExpirationTime),
- createResponseExtensions(commandOperations.getTotalCost(), feeRenew));
+ return responseBuilder
+ .setResData(DomainRenewData.create(targetId, newExpirationTime))
+ .setExtensions(createResponseExtensions(commandOperations.getTotalCost(), feeRenew))
+ .build();
}
private void verifyRenewAllowed(
@@ -199,7 +203,7 @@ public final class DomainRenewFlow extends Flow implements TransactionalFlow {
}
private OneTime createRenewBillingEvent(
- String tld, Money renewCost, int years, HistoryEntry historyEntry) {
+ String tld, Money renewCost, int years, HistoryEntry historyEntry, DateTime now) {
return new BillingEvent.OneTime.Builder()
.setReason(Reason.RENEW)
.setTargetId(targetId)
diff --git a/java/google/registry/flows/domain/DomainRestoreRequestFlow.java b/java/google/registry/flows/domain/DomainRestoreRequestFlow.java
index f85838f06..c2f60e313 100644
--- a/java/google/registry/flows/domain/DomainRestoreRequestFlow.java
+++ b/java/google/registry/flows/domain/DomainRestoreRequestFlow.java
@@ -26,7 +26,6 @@ import static google.registry.flows.domain.DomainFlowUtils.validateFeeChallenge;
import static google.registry.flows.domain.DomainFlowUtils.verifyNotReserved;
import static google.registry.flows.domain.DomainFlowUtils.verifyPremiumNameIsNotBlocked;
import static google.registry.model.domain.fee.Fee.FEE_UPDATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
@@ -40,8 +39,8 @@ import google.registry.flows.EppException;
import google.registry.flows.EppException.CommandUseErrorException;
import google.registry.flows.EppException.StatusProhibitsOperationException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
+import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.domain.TldSpecificLogicProxy.EppCommandOperations;
@@ -60,8 +59,9 @@ import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.rgp.RgpUpdateExtension;
import google.registry.model.eppcommon.AuthInfo;
+import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.ResourceCommand;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.registry.Registry;
import google.registry.model.reporting.HistoryEntry;
@@ -103,37 +103,40 @@ import org.joda.time.DateTime;
* @error {@link DomainRestoreRequestFlow.DomainNotEligibleForRestoreException}
* @error {@link DomainRestoreRequestFlow.RestoreCommandIncludesChangesException}
*/
-public final class DomainRestoreRequestFlow extends Flow implements TransactionalFlow {
+public final class DomainRestoreRequestFlow implements TransactionalFlow {
@Inject ResourceCommand resourceCommand;
@Inject ExtensionManager extensionManager;
+ @Inject EppInput eppInput;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
+ @Inject @Superuser boolean isSuperuser;
@Inject HistoryEntry.Builder historyBuilder;
@Inject DnsQueue dnsQueue;
+ @Inject EppResponse.Builder responseBuilder;
@Inject DomainRestoreRequestFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(MetadataExtension.class, RgpUpdateExtension.class);
extensionManager.registerAsGroup(FEE_UPDATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
Update command = (Update) resourceCommand;
+ DateTime now = ofy().getTransactionTime();
DomainResource existingDomain = loadAndVerifyExistence(DomainResource.class, targetId, now);
Money restoreCost = Registry.get(existingDomain.getTld()).getStandardRestoreCost();
EppCommandOperations renewCommandOperations = TldSpecificLogicProxy.getRenewPrice(
Registry.get(existingDomain.getTld()), targetId, clientId, now, 1, eppInput);
FeeTransformCommandExtension feeUpdate = eppInput.getFirstExtensionOfClasses(
FEE_UPDATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
- verifyRestoreAllowed(
- command, existingDomain, restoreCost, renewCommandOperations.getTotalCost(), feeUpdate);
- HistoryEntry historyEntry = buildHistory(existingDomain);
+ Money totalCost = renewCommandOperations.getTotalCost();
+ verifyRestoreAllowed(command, existingDomain, restoreCost, totalCost, feeUpdate, now);
+ HistoryEntry historyEntry = buildHistory(existingDomain, now);
ImmutableSet.Builder entitiesToSave = new ImmutableSet.Builder<>();
entitiesToSave.addAll(
- createRestoreAndRenewBillingEvents(
- historyEntry, restoreCost, renewCommandOperations.getTotalCost()));
+ createRestoreAndRenewBillingEvents(historyEntry, restoreCost, totalCost, now));
// We don't preserve the original expiration time of the domain when we restore, since doing so
// would require us to know if they received a grace period refund when they deleted the domain,
// and to charge them for that again. Instead, we just say that all restores get a fresh year of
@@ -163,13 +166,12 @@ public final class DomainRestoreRequestFlow extends Flow implements Transactiona
ofy().save().entities(entitiesToSave.build());
ofy().delete().key(existingDomain.getDeletePollMessage());
dnsQueue.addDomainRefreshTask(existingDomain.getFullyQualifiedDomainName());
- return createOutput(
- SUCCESS,
- null,
- createResponseExtensions(restoreCost, renewCommandOperations.getTotalCost(), feeUpdate));
+ return responseBuilder
+ .setExtensions(createResponseExtensions(restoreCost, totalCost, feeUpdate))
+ .build();
}
- private HistoryEntry buildHistory(DomainResource existingDomain) {
+ private HistoryEntry buildHistory(DomainResource existingDomain, DateTime now) {
return historyBuilder
.setType(HistoryEntry.Type.DOMAIN_RESTORE)
.setModificationTime(now)
@@ -182,7 +184,8 @@ public final class DomainRestoreRequestFlow extends Flow implements Transactiona
DomainResource existingDomain,
Money restoreCost,
Money renewCost,
- FeeTransformCommandExtension feeUpdate) throws EppException {
+ FeeTransformCommandExtension feeUpdate,
+ DateTime now) throws EppException {
verifyOptionalAuthInfoForResource(authInfo, existingDomain);
if (!isSuperuser) {
verifyResourceOwnership(clientId, existingDomain);
@@ -202,14 +205,14 @@ public final class DomainRestoreRequestFlow extends Flow implements Transactiona
}
private ImmutableSet createRestoreAndRenewBillingEvents(
- HistoryEntry historyEntry, Money restoreCost, Money renewCost) {
+ HistoryEntry historyEntry, Money restoreCost, Money renewCost, DateTime now) {
// Bill for the restore.
- BillingEvent.OneTime restoreEvent = createRestoreBillingEvent(historyEntry, restoreCost);
+ BillingEvent.OneTime restoreEvent = createRestoreBillingEvent(historyEntry, restoreCost, now);
// Create a new autorenew billing event and poll message starting at the new expiration time.
// Also bill for the 1 year cost of a domain renew. This is to avoid registrants being able to
// game the system for premium names by renewing, deleting, and then restoring to get a free
// year. Note that this billing event has no grace period; it is effective immediately.
- BillingEvent.OneTime renewEvent = createRenewBillingEvent(historyEntry, renewCost);
+ BillingEvent.OneTime renewEvent = createRenewBillingEvent(historyEntry, renewCost, now);
return ImmutableSet.of(restoreEvent, renewEvent);
}
@@ -229,21 +232,22 @@ public final class DomainRestoreRequestFlow extends Flow implements Transactiona
.build();
}
- private OneTime createRenewBillingEvent(HistoryEntry historyEntry, Money renewCost) {
- return prepareBillingEvent(historyEntry, renewCost)
+ private OneTime createRenewBillingEvent(
+ HistoryEntry historyEntry, Money renewCost, DateTime now) {
+ return prepareBillingEvent(historyEntry, renewCost, now)
.setPeriodYears(1)
.setReason(Reason.RENEW)
.build();
}
private BillingEvent.OneTime createRestoreBillingEvent(
- HistoryEntry historyEntry, Money restoreCost) {
- return prepareBillingEvent(historyEntry, restoreCost)
+ HistoryEntry historyEntry, Money restoreCost, DateTime now) {
+ return prepareBillingEvent(historyEntry, restoreCost, now)
.setReason(Reason.RESTORE)
.build();
}
- private Builder prepareBillingEvent(HistoryEntry historyEntry, Money cost) {
+ private Builder prepareBillingEvent(HistoryEntry historyEntry, Money cost, DateTime now) {
return new BillingEvent.OneTime.Builder()
.setTargetId(targetId)
.setClientId(clientId)
diff --git a/java/google/registry/flows/domain/DomainTransferApproveFlow.java b/java/google/registry/flows/domain/DomainTransferApproveFlow.java
index 02c909169..7119fdb7d 100644
--- a/java/google/registry/flows/domain/DomainTransferApproveFlow.java
+++ b/java/google/registry/flows/domain/DomainTransferApproveFlow.java
@@ -27,7 +27,6 @@ import static google.registry.flows.domain.DomainFlowUtils.createGainingTransfer
import static google.registry.flows.domain.DomainFlowUtils.createTransferResponse;
import static google.registry.flows.domain.DomainFlowUtils.updateAutorenewRecurrenceEndTime;
import static google.registry.model.domain.DomainResource.extendRegistrationWithCap;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.pricing.PricingEngineProxy.getDomainRenewCost;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
@@ -38,7 +37,6 @@ import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
@@ -51,7 +49,7 @@ import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.eppcommon.AuthInfo;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.registry.Registry;
import google.registry.model.reporting.HistoryEntry;
@@ -78,13 +76,14 @@ import org.joda.time.DateTime;
* @error {@link google.registry.flows.exceptions.NotPendingTransferException}
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
*/
-public final class DomainTransferApproveFlow extends Flow implements TransactionalFlow {
+public final class DomainTransferApproveFlow implements TransactionalFlow {
@Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject HistoryEntry.Builder historyBuilder;
+ @Inject EppResponse.Builder responseBuilder;
@Inject DomainTransferApproveFlow() {}
/**
@@ -92,10 +91,11 @@ public final class DomainTransferApproveFlow extends Flow implements Transaction
* {@link DomainResource#cloneProjectedAtTime} which handles implicit server approvals.
*/
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(MetadataExtension.class);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
+ DateTime now = ofy().getTransactionTime();
DomainResource existingDomain = loadAndVerifyExistence(DomainResource.class, targetId, now);
verifyOptionalAuthInfoForResource(authInfo, existingDomain);
verifyHasPendingTransfer(existingDomain);
@@ -187,9 +187,9 @@ public final class DomainTransferApproveFlow extends Flow implements Transaction
// Delete the billing event and poll messages that were written in case the transfer would have
// been implicitly server approved.
ofy().delete().keys(existingDomain.getTransferData().getServerApproveEntities());
- return createOutput(
- SUCCESS,
- createTransferResponse(
- targetId, newDomain.getTransferData(), newDomain.getRegistrationExpirationTime()));
+ return responseBuilder
+ .setResData(createTransferResponse(
+ targetId, newDomain.getTransferData(), newDomain.getRegistrationExpirationTime()))
+ .build();
}
}
diff --git a/java/google/registry/flows/domain/DomainTransferCancelFlow.java b/java/google/registry/flows/domain/DomainTransferCancelFlow.java
index 25dfc837c..5d5d2ba41 100644
--- a/java/google/registry/flows/domain/DomainTransferCancelFlow.java
+++ b/java/google/registry/flows/domain/DomainTransferCancelFlow.java
@@ -24,7 +24,6 @@ import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToT
import static google.registry.flows.domain.DomainFlowUtils.createLosingTransferPollMessage;
import static google.registry.flows.domain.DomainFlowUtils.createTransferResponse;
import static google.registry.flows.domain.DomainFlowUtils.updateAutorenewRecurrenceEndTime;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
@@ -32,7 +31,6 @@ import com.google.common.base.Optional;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
@@ -40,10 +38,11 @@ import google.registry.model.ImmutableObject;
import google.registry.model.domain.DomainResource;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppcommon.AuthInfo;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.TransferStatus;
import javax.inject.Inject;
+import org.joda.time.DateTime;
/**
* An EPP flow that cancels a pending transfer on a domain.
@@ -63,20 +62,22 @@ import javax.inject.Inject;
* @error {@link google.registry.flows.exceptions.NotTransferInitiatorException}
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
*/
-public final class DomainTransferCancelFlow extends Flow implements TransactionalFlow {
+public final class DomainTransferCancelFlow implements TransactionalFlow {
@Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject HistoryEntry.Builder historyBuilder;
+ @Inject EppResponse.Builder responseBuilder;
@Inject DomainTransferCancelFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(MetadataExtension.class);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
+ DateTime now = ofy().getTransactionTime();
DomainResource existingDomain = loadAndVerifyExistence(DomainResource.class, targetId, now);
verifyOptionalAuthInfoForResource(authInfo, existingDomain);
verifyHasPendingTransfer(existingDomain);
@@ -100,8 +101,8 @@ public final class DomainTransferCancelFlow extends Flow implements Transactiona
// Delete the billing event and poll messages that were written in case the transfer would have
// been implicitly server approved.
ofy().delete().keys(existingDomain.getTransferData().getServerApproveEntities());
- return createOutput(
- SUCCESS,
- createTransferResponse(targetId, newDomain.getTransferData(), null));
+ return responseBuilder
+ .setResData(createTransferResponse(targetId, newDomain.getTransferData(), null))
+ .build();
}
}
diff --git a/java/google/registry/flows/domain/DomainTransferQueryFlow.java b/java/google/registry/flows/domain/DomainTransferQueryFlow.java
index 975bef0b6..eec2ca1f9 100644
--- a/java/google/registry/flows/domain/DomainTransferQueryFlow.java
+++ b/java/google/registry/flows/domain/DomainTransferQueryFlow.java
@@ -19,7 +19,6 @@ import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
import static google.registry.flows.domain.DomainFlowUtils.createTransferResponse;
import static google.registry.model.domain.DomainResource.extendRegistrationWithCap;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import com.google.common.base.Optional;
import google.registry.flows.EppException;
@@ -31,9 +30,10 @@ import google.registry.flows.exceptions.NoTransferHistoryToQueryException;
import google.registry.flows.exceptions.NotAuthorizedToViewTransferException;
import google.registry.model.domain.DomainResource;
import google.registry.model.eppcommon.AuthInfo;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferStatus;
+import google.registry.util.Clock;
import javax.inject.Inject;
import org.joda.time.DateTime;
@@ -52,18 +52,21 @@ import org.joda.time.DateTime;
* @error {@link google.registry.flows.exceptions.NoTransferHistoryToQueryException}
* @error {@link google.registry.flows.exceptions.NotAuthorizedToViewTransferException}
*/
-public final class DomainTransferQueryFlow extends Flow {
+public final class DomainTransferQueryFlow implements Flow {
@Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
+ @Inject Clock clock;
+ @Inject EppResponse.Builder responseBuilder;
@Inject DomainTransferQueryFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.validate(); // There are no legal extensions for this flow.
validateClientIsLoggedIn(clientId);
+ DateTime now = clock.nowUtc();
DomainResource domain = loadAndVerifyExistence(DomainResource.class, targetId, now);
verifyOptionalAuthInfoForResource(authInfo, domain);
// Most of the fields on the transfer response are required, so there's no way to return valid
@@ -88,6 +91,8 @@ public final class DomainTransferQueryFlow extends Flow {
domain.getRegistrationExpirationTime(),
transferData.getExtendedRegistrationYears());
}
- return createOutput(SUCCESS, createTransferResponse(targetId, transferData, newExpirationTime));
+ return responseBuilder
+ .setResData(createTransferResponse(targetId, transferData, newExpirationTime))
+ .build();
}
}
diff --git a/java/google/registry/flows/domain/DomainTransferRejectFlow.java b/java/google/registry/flows/domain/DomainTransferRejectFlow.java
index b2cdbdc77..94f03c11e 100644
--- a/java/google/registry/flows/domain/DomainTransferRejectFlow.java
+++ b/java/google/registry/flows/domain/DomainTransferRejectFlow.java
@@ -24,7 +24,6 @@ import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToT
import static google.registry.flows.domain.DomainFlowUtils.createGainingTransferPollMessage;
import static google.registry.flows.domain.DomainFlowUtils.createTransferResponse;
import static google.registry.flows.domain.DomainFlowUtils.updateAutorenewRecurrenceEndTime;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
@@ -32,7 +31,6 @@ import com.google.common.base.Optional;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
@@ -40,10 +38,11 @@ import google.registry.model.ImmutableObject;
import google.registry.model.domain.DomainResource;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppcommon.AuthInfo;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.TransferStatus;
import javax.inject.Inject;
+import org.joda.time.DateTime;
/**
* An EPP flow that rejects a pending transfer on a domain.
@@ -63,20 +62,22 @@ import javax.inject.Inject;
* @error {@link google.registry.flows.exceptions.NotPendingTransferException}
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
*/
-public final class DomainTransferRejectFlow extends Flow implements TransactionalFlow {
+public final class DomainTransferRejectFlow implements TransactionalFlow {
@Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject HistoryEntry.Builder historyBuilder;
+ @Inject EppResponse.Builder responseBuilder;
@Inject DomainTransferRejectFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(MetadataExtension.class);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
+ DateTime now = ofy().getTransactionTime();
DomainResource existingDomain = loadAndVerifyExistence(DomainResource.class, targetId, now);
HistoryEntry historyEntry = historyBuilder
.setType(HistoryEntry.Type.DOMAIN_TRANSFER_REJECT)
@@ -100,8 +101,8 @@ public final class DomainTransferRejectFlow extends Flow implements Transactiona
// Delete the billing event and poll messages that were written in case the transfer would have
// been implicitly server approved.
ofy().delete().keys(existingDomain.getTransferData().getServerApproveEntities());
- return createOutput(
- SUCCESS,
- createTransferResponse(targetId, newDomain.getTransferData(), null));
+ return responseBuilder
+ .setResData(createTransferResponse(targetId, newDomain.getTransferData(), null))
+ .build();
}
}
diff --git a/java/google/registry/flows/domain/DomainTransferRequestFlow.java b/java/google/registry/flows/domain/DomainTransferRequestFlow.java
index 89d7bc804..953691ddf 100644
--- a/java/google/registry/flows/domain/DomainTransferRequestFlow.java
+++ b/java/google/registry/flows/domain/DomainTransferRequestFlow.java
@@ -41,8 +41,8 @@ import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
+import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.exceptions.AlreadyPendingTransferException;
@@ -61,8 +61,10 @@ import google.registry.model.domain.flags.FlagsTransferCommandExtension;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppcommon.StatusValue;
+import google.registry.model.eppcommon.Trid;
+import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.ResourceCommand;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.registry.Registry;
import google.registry.model.reporting.HistoryEntry;
@@ -106,7 +108,7 @@ import org.joda.time.Duration;
* @error {@link DomainFlowUtils.PremiumNameBlockedException}
* @error {@link DomainFlowUtils.UnsupportedFeeAttributeException}
*/
-public final class DomainTransferRequestFlow extends Flow implements TransactionalFlow {
+public final class DomainTransferRequestFlow implements TransactionalFlow {
private static final ImmutableSet DISALLOWED_STATUSES = ImmutableSet.of(
StatusValue.CLIENT_TRANSFER_PROHIBITED,
@@ -115,22 +117,27 @@ public final class DomainTransferRequestFlow extends Flow implements Transaction
@Inject ResourceCommand resourceCommand;
@Inject ExtensionManager extensionManager;
+ @Inject EppInput eppInput;
@Inject Optional authInfo;
@Inject @ClientId String gainingClientId;
@Inject @TargetId String targetId;
+ @Inject @Superuser boolean isSuperuser;
@Inject HistoryEntry.Builder historyBuilder;
+ @Inject Trid trid;
+ @Inject EppResponse.Builder responseBuilder;
@Inject DomainTransferRequestFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(FlagsTransferCommandExtension.class, MetadataExtension.class);
extensionManager.registerAsGroup(FEE_TRANSFER_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
extensionManager.validate();
validateClientIsLoggedIn(gainingClientId);
Period period = ((Transfer) resourceCommand).getPeriod();
int years = period.getValue();
+ DateTime now = ofy().getTransactionTime();
DomainResource existingDomain = loadAndVerifyExistence(DomainResource.class, targetId, now);
- verifyTransferAllowed(existingDomain, period);
+ verifyTransferAllowed(existingDomain, period, now);
String tld = existingDomain.getTld();
Registry registry = Registry.get(tld);
// The cost of the renewal implied by a transfer.
@@ -139,7 +146,7 @@ public final class DomainTransferRequestFlow extends Flow implements Transaction
FeeTransformCommandExtension feeTransfer = eppInput.getFirstExtensionOfClasses(
FEE_TRANSFER_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
validateFeeChallenge(targetId, tld, now, feeTransfer, renewCost);
- HistoryEntry historyEntry = buildHistory(period, existingDomain);
+ HistoryEntry historyEntry = buildHistory(period, existingDomain, now);
DateTime automaticTransferTime = now.plus(registry.getAutomaticTransferLength());
// The new expiration time if there is a server approval.
DateTime serverApproveNewExpirationTime = extendRegistrationWithCap(
@@ -152,10 +159,11 @@ public final class DomainTransferRequestFlow extends Flow implements Transaction
historyEntry,
existingDomain,
renewCost,
- years);
+ years,
+ now);
// Create the transfer data that represents the pending transfer.
TransferData pendingTransferData = createPendingTransferData(
- createTransferDataBuilder(existingDomain, automaticTransferTime, years),
+ createTransferDataBuilder(existingDomain, automaticTransferTime, years, now),
serverApproveEntities);
// Create a poll message to notify the losing registrar that a transfer was requested.
PollMessage requestPollMessage = createLosingTransferPollMessage(
@@ -166,7 +174,7 @@ public final class DomainTransferRequestFlow extends Flow implements Transaction
// cloneProjectedAtTime() will replace these old autorenew entities with the server approve ones
// that we've created in this flow and stored in pendingTransferData.
updateAutorenewRecurrenceEndTime(existingDomain, automaticTransferTime);
- handleExtraFlowLogic(years, existingDomain, historyEntry);
+ handleExtraFlowLogic(years, existingDomain, historyEntry, now);
DomainResource newDomain = existingDomain.asBuilder()
.setTransferData(pendingTransferData)
.addStatusValue(StatusValue.PENDING_TRANSFER)
@@ -177,13 +185,14 @@ public final class DomainTransferRequestFlow extends Flow implements Transaction
.addAll(serverApproveEntities)
.build())
.now();
- return createOutput(
- SUCCESS_WITH_ACTION_PENDING,
- createResponse(period, existingDomain, newDomain),
- createResponseExtensions(renewCost, feeTransfer));
+ return responseBuilder
+ .setResultFromCode(SUCCESS_WITH_ACTION_PENDING)
+ .setResData(createResponse(period, existingDomain, newDomain, now))
+ .setExtensions(createResponseExtensions(renewCost, feeTransfer))
+ .build();
}
- private void verifyTransferAllowed(DomainResource existingDomain, Period period)
+ private void verifyTransferAllowed(DomainResource existingDomain, Period period, DateTime now)
throws EppException {
verifyNoDisallowedStatuses(existingDomain, DISALLOWED_STATUSES);
verifyRequiredAuthInfoForResourceTransfer(authInfo, existingDomain);
@@ -202,7 +211,7 @@ public final class DomainTransferRequestFlow extends Flow implements Transaction
}
}
- private HistoryEntry buildHistory(Period period, DomainResource existingResource) {
+ private HistoryEntry buildHistory(Period period, DomainResource existingResource, DateTime now) {
return historyBuilder
.setType(HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST)
.setPeriod(period)
@@ -231,10 +240,11 @@ public final class DomainTransferRequestFlow extends Flow implements Transaction
HistoryEntry historyEntry,
DomainResource existingDomain,
Money renewCost,
- int years) {
+ int years,
+ DateTime now) {
// Create a TransferData for the server-approve case to use for the speculative poll messages.
TransferData serverApproveTransferData =
- createTransferDataBuilder(existingDomain, automaticTransferTime, years)
+ createTransferDataBuilder(existingDomain, automaticTransferTime, years, now)
.setTransferStatus(TransferStatus.SERVER_APPROVED)
.build();
Registry registry = Registry.get(existingDomain.getTld());
@@ -333,9 +343,7 @@ public final class DomainTransferRequestFlow extends Flow implements Transaction
}
private Builder createTransferDataBuilder(
- DomainResource existingDomain,
- DateTime automaticTransferTime,
- int years) {
+ DomainResource existingDomain, DateTime automaticTransferTime, int years, DateTime now) {
return new TransferData.Builder()
.setTransferRequestTrid(trid)
.setTransferRequestTime(now)
@@ -366,17 +374,23 @@ public final class DomainTransferRequestFlow extends Flow implements Transaction
}
private void handleExtraFlowLogic(
- int years, DomainResource existingDomain, HistoryEntry historyEntry) throws EppException {
+ int years, DomainResource existingDomain, HistoryEntry historyEntry, DateTime now)
+ throws EppException {
Optional extraFlowLogic =
RegistryExtraFlowLogicProxy.newInstanceForDomain(existingDomain);
if (extraFlowLogic.isPresent()) {
extraFlowLogic.get().performAdditionalDomainTransferLogic(
- existingDomain, gainingClientId, now, years, eppInput, historyEntry);
+ existingDomain,
+ gainingClientId,
+ now,
+ years,
+ eppInput,
+ historyEntry);
}
}
private DomainTransferResponse createResponse(
- Period period, DomainResource existingDomain, DomainResource newDomain) {
+ Period period, DomainResource existingDomain, DomainResource newDomain, DateTime now) {
// If the registration were approved this instant, this is what the new expiration would be,
// because we cap at 10 years from the moment of approval. This is different than the server
// approval new expiration time, which is capped at 10 years from the server approve time.
diff --git a/java/google/registry/flows/domain/DomainUpdateFlow.java b/java/google/registry/flows/domain/DomainUpdateFlow.java
index 30ec444bb..fa865f4e4 100644
--- a/java/google/registry/flows/domain/DomainUpdateFlow.java
+++ b/java/google/registry/flows/domain/DomainUpdateFlow.java
@@ -38,7 +38,6 @@ import static google.registry.flows.domain.DomainFlowUtils.validateRequiredConta
import static google.registry.flows.domain.DomainFlowUtils.verifyClientUpdateNotProhibited;
import static google.registry.flows.domain.DomainFlowUtils.verifyNotInPendingDelete;
import static google.registry.model.domain.fee.Fee.FEE_UPDATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.util.DateTimeUtils.earliestOf;
@@ -49,8 +48,8 @@ import com.googlecode.objectify.Key;
import google.registry.dns.DnsQueue;
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
+import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.domain.DomainFlowUtils.FeesRequiredForNonFreeUpdateException;
@@ -70,8 +69,9 @@ import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.secdns.SecDnsUpdateExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppcommon.StatusValue;
+import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.ResourceCommand;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.registry.Registry;
import google.registry.model.reporting.HistoryEntry;
import javax.inject.Inject;
@@ -121,7 +121,7 @@ import org.joda.time.DateTime;
* @error {@link DomainFlowUtils.TooManyNameserversException}
* @error {@link DomainFlowUtils.UrgentAttributeNotSupportedException}
*/
-public final class DomainUpdateFlow extends Flow implements TransactionalFlow {
+public final class DomainUpdateFlow implements TransactionalFlow {
/**
* Note that CLIENT_UPDATE_PROHIBITED is intentionally not in this list. This is because it
@@ -134,15 +134,18 @@ public final class DomainUpdateFlow extends Flow implements TransactionalFlow {
@Inject ResourceCommand resourceCommand;
@Inject ExtensionManager extensionManager;
+ @Inject EppInput eppInput;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
+ @Inject @Superuser boolean isSuperuser;
@Inject HistoryEntry.Builder historyBuilder;
@Inject DnsQueue dnsQueue;
+ @Inject EppResponse.Builder responseBuilder;
@Inject DomainUpdateFlow() {}
@Override
- public EppOutput run() throws EppException {
+ public EppResponse run() throws EppException {
extensionManager.register(
FlagsUpdateCommandExtension.class,
MetadataExtension.class,
@@ -150,37 +153,38 @@ public final class DomainUpdateFlow extends Flow implements TransactionalFlow {
extensionManager.registerAsGroup(FEE_UPDATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
+ DateTime now = ofy().getTransactionTime();
Update command = cloneAndLinkReferences((Update) resourceCommand, now);
DomainResource existingDomain = loadAndVerifyExistence(DomainResource.class, targetId, now);
- verifyUpdateAllowed(command, existingDomain);
- HistoryEntry historyEntry = buildHistoryEntry(existingDomain);
- DomainResource newDomain = performUpdate(command, existingDomain);
+ verifyUpdateAllowed(command, existingDomain, now);
+ HistoryEntry historyEntry = buildHistoryEntry(existingDomain, now);
+ DomainResource newDomain = performUpdate(command, existingDomain, now);
// If the new domain is in the sunrush add grace period and is now publishable to DNS because we
// have added nameserver or removed holds, we have to convert it to a standard add grace period.
if (newDomain.shouldPublishToDns()) {
for (GracePeriod gracePeriod : newDomain.getGracePeriods()) {
if (gracePeriod.isSunrushAddGracePeriod()) {
- newDomain = convertSunrushAddToAdd(newDomain, gracePeriod, historyEntry);
+ newDomain = convertSunrushAddToAdd(newDomain, gracePeriod, historyEntry, now);
break; // There can only be one sunrush add grace period.
}
}
}
validateNewState(newDomain);
dnsQueue.addDomainRefreshTask(targetId);
- handleExtraFlowLogic(existingDomain, historyEntry);
+ handleExtraFlowLogic(existingDomain, historyEntry, now);
ImmutableList.Builder entitiesToSave = new ImmutableList.Builder<>();
entitiesToSave.add(newDomain, historyEntry);
Optional statusUpdateBillingEvent =
- createBillingEventForStatusUpdates(existingDomain, newDomain, historyEntry);
+ createBillingEventForStatusUpdates(existingDomain, newDomain, historyEntry, now);
if (statusUpdateBillingEvent.isPresent()) {
entitiesToSave.add(statusUpdateBillingEvent.get());
}
ofy().save().entities(entitiesToSave.build());
- return createOutput(SUCCESS);
+ return responseBuilder.build();
}
/** Fail if the object doesn't exist or was deleted. */
- private void verifyUpdateAllowed(Update command, DomainResource existingDomain)
+ private void verifyUpdateAllowed(Update command, DomainResource existingDomain, DateTime now)
throws EppException {
verifyNoDisallowedStatuses(existingDomain, UPDATE_DISALLOWED_STATUSES);
verifyOptionalAuthInfoForResource(authInfo, existingDomain);
@@ -219,7 +223,7 @@ public final class DomainUpdateFlow extends Flow implements TransactionalFlow {
tld, add.getNameserverFullyQualifiedHostNames());
}
- private HistoryEntry buildHistoryEntry(DomainResource existingDomain) {
+ private HistoryEntry buildHistoryEntry(DomainResource existingDomain, DateTime now) {
return historyBuilder
.setType(HistoryEntry.Type.DOMAIN_UPDATE)
.setModificationTime(now)
@@ -227,7 +231,7 @@ public final class DomainUpdateFlow extends Flow implements TransactionalFlow {
.build();
}
- private DomainResource performUpdate(Update command, DomainResource domain)
+ private DomainResource performUpdate(Update command, DomainResource domain, DateTime now)
throws EppException {
AddRemove add = command.getInnerAdd();
AddRemove remove = command.getInnerRemove();
@@ -255,12 +259,12 @@ public final class DomainUpdateFlow extends Flow implements TransactionalFlow {
}
private DomainResource convertSunrushAddToAdd(
- DomainResource newDomain, GracePeriod gracePeriod, HistoryEntry historyEntry) {
+ DomainResource newDomain, GracePeriod gracePeriod, HistoryEntry historyEntry, DateTime now) {
// Cancel the billing event for the sunrush add and replace it with a new billing event.
BillingEvent.Cancellation billingEventCancellation =
BillingEvent.Cancellation.forGracePeriod(gracePeriod, historyEntry, targetId);
BillingEvent.OneTime billingEvent =
- createBillingEventForSunrushConversion(newDomain, historyEntry, gracePeriod);
+ createBillingEventForSunrushConversion(newDomain, historyEntry, gracePeriod, now);
ofy().save().entities(billingEvent, billingEventCancellation);
// Modify the grace periods on the domain.
return newDomain.asBuilder()
@@ -270,7 +274,10 @@ public final class DomainUpdateFlow extends Flow implements TransactionalFlow {
}
private BillingEvent.OneTime createBillingEventForSunrushConversion(
- DomainResource existingDomain, HistoryEntry historyEntry, GracePeriod sunrushAddGracePeriod) {
+ DomainResource existingDomain,
+ HistoryEntry historyEntry,
+ GracePeriod sunrushAddGracePeriod,
+ DateTime now) {
// Compute the expiration time of the add grace period. We will not allow it to be after the
// sunrush add grace period expiration time (i.e. you can't get extra add grace period by
// setting a nameserver).
@@ -304,7 +311,10 @@ public final class DomainUpdateFlow extends Flow implements TransactionalFlow {
/** Some status updates cost money. Bill only once no matter how many of them are changed. */
private Optional createBillingEventForStatusUpdates(
- DomainResource existingDomain, DomainResource newDomain, HistoryEntry historyEntry) {
+ DomainResource existingDomain,
+ DomainResource newDomain,
+ HistoryEntry historyEntry,
+ DateTime now) {
MetadataExtension metadataExtension = eppInput.getSingleExtension(MetadataExtension.class);
if (metadataExtension != null && metadataExtension.getRequestedByRegistrar()) {
for (StatusValue statusValue
@@ -326,8 +336,8 @@ public final class DomainUpdateFlow extends Flow implements TransactionalFlow {
return Optional.absent();
}
- private void handleExtraFlowLogic(DomainResource existingDomain, HistoryEntry historyEntry)
- throws EppException {
+ private void handleExtraFlowLogic(
+ DomainResource existingDomain, HistoryEntry historyEntry, DateTime now) throws EppException {
Optional extraFlowLogic =
RegistryExtraFlowLogicProxy.newInstanceForDomain(existingDomain);
if (extraFlowLogic.isPresent()) {
diff --git a/java/google/registry/flows/host/HostCheckFlow.java b/java/google/registry/flows/host/HostCheckFlow.java
index d26e0c6fc..f520ea8a8 100644
--- a/java/google/registry/flows/host/HostCheckFlow.java
+++ b/java/google/registry/flows/host/HostCheckFlow.java
@@ -17,7 +17,6 @@ package google.registry.flows.host;
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.verifyTargetIdCount;
import static google.registry.model.EppResourceUtils.checkResourcesExist;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import com.google.common.collect.ImmutableList;
import google.registry.config.ConfigModule.Config;
@@ -28,9 +27,10 @@ import google.registry.flows.FlowModule.ClientId;
import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppoutput.CheckData.HostCheck;
import google.registry.model.eppoutput.CheckData.HostCheckData;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.host.HostCommand.Check;
import google.registry.model.host.HostResource;
+import google.registry.util.Clock;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
@@ -42,26 +42,28 @@ import javax.inject.Inject;
*
* @error {@link google.registry.flows.exceptions.TooManyResourceChecksException}
*/
-public final class HostCheckFlow extends Flow {
+public final class HostCheckFlow implements Flow {
@Inject ResourceCommand resourceCommand;
@Inject @ClientId String clientId;
@Inject ExtensionManager extensionManager;
@Inject @Config("maxChecks") int maxChecks;
+ @Inject Clock clock;
+ @Inject EppResponse.Builder responseBuilder;
@Inject HostCheckFlow() {}
@Override
- protected final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.validate(); // There are no legal extensions for this flow.
validateClientIsLoggedIn(clientId);
List targetIds = ((Check) resourceCommand).getTargetIds();
verifyTargetIdCount(targetIds, maxChecks);
- Set existingIds = checkResourcesExist(HostResource.class, targetIds, now);
+ Set existingIds = checkResourcesExist(HostResource.class, targetIds, clock.nowUtc());
ImmutableList.Builder checks = new ImmutableList.Builder<>();
for (String id : targetIds) {
boolean unused = !existingIds.contains(id);
checks.add(HostCheck.create(unused, id, unused ? null : "In use"));
}
- return createOutput(SUCCESS, HostCheckData.create(checks.build()));
+ return responseBuilder.setResData(HostCheckData.create(checks.build())).build();
}
}
diff --git a/java/google/registry/flows/host/HostCreateFlow.java b/java/google/registry/flows/host/HostCreateFlow.java
index 683e177ca..4736c4149 100644
--- a/java/google/registry/flows/host/HostCreateFlow.java
+++ b/java/google/registry/flows/host/HostCreateFlow.java
@@ -20,7 +20,6 @@ import static google.registry.flows.host.HostFlowUtils.lookupSuperordinateDomain
import static google.registry.flows.host.HostFlowUtils.validateHostName;
import static google.registry.flows.host.HostFlowUtils.verifyDomainIsSameRegistrar;
import static google.registry.model.EppResourceUtils.createContactHostRoid;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.util.CollectionUtils.isNullOrEmpty;
import static google.registry.util.CollectionUtils.union;
@@ -33,7 +32,6 @@ import google.registry.flows.EppException;
import google.registry.flows.EppException.ParameterValueRangeErrorException;
import google.registry.flows.EppException.RequiredParameterMissingException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
@@ -42,7 +40,7 @@ import google.registry.model.domain.DomainResource;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppoutput.CreateData.HostCreateData;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.host.HostCommand.Create;
import google.registry.model.host.HostResource;
import google.registry.model.host.HostResource.Builder;
@@ -51,6 +49,7 @@ import google.registry.model.index.ForeignKeyIndex;
import google.registry.model.ofy.ObjectifyService;
import google.registry.model.reporting.HistoryEntry;
import javax.inject.Inject;
+import org.joda.time.DateTime;
/**
* An EPP flow that creates a new host.
@@ -70,7 +69,7 @@ import javax.inject.Inject;
* @error {@link SubordinateHostMustHaveIpException}
* @error {@link UnexpectedExternalHostIpException}
*/
-public final class HostCreateFlow extends Flow implements TransactionalFlow {
+public final class HostCreateFlow implements TransactionalFlow {
@Inject ResourceCommand resourceCommand;
@Inject ExtensionManager extensionManager;
@@ -78,14 +77,16 @@ public final class HostCreateFlow extends Flow implements TransactionalFlow {
@Inject @TargetId String targetId;
@Inject HistoryEntry.Builder historyBuilder;
@Inject DnsQueue dnsQueue;
+ @Inject EppResponse.Builder responseBuilder;
@Inject HostCreateFlow() {}
@Override
- protected final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(MetadataExtension.class);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
Create command = (Create) resourceCommand;
+ DateTime now = ofy().getTransactionTime();
verifyResourceDoesNotExist(HostResource.class, targetId, now);
// The superordinate domain of the host object if creating an in-bailiwick host, or null if
// creating an external host. This is looked up before we actually create the Host object so
@@ -130,7 +131,7 @@ public final class HostCreateFlow extends Flow implements TransactionalFlow {
dnsQueue.addHostRefreshTask(targetId);
}
ofy().save().entities(entitiesToSave);
- return createOutput(SUCCESS, HostCreateData.create(targetId, now));
+ return responseBuilder.setResData(HostCreateData.create(targetId, now)).build();
}
/** Subordinate hosts must have an ip address. */
diff --git a/java/google/registry/flows/host/HostDeleteFlow.java b/java/google/registry/flows/host/HostDeleteFlow.java
index e6f1a21d3..e5cb23358 100644
--- a/java/google/registry/flows/host/HostDeleteFlow.java
+++ b/java/google/registry/flows/host/HostDeleteFlow.java
@@ -29,8 +29,8 @@ import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
+import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.async.AsyncFlowEnqueuer;
@@ -38,10 +38,11 @@ import google.registry.model.domain.DomainBase;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppcommon.StatusValue;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.host.HostResource;
import google.registry.model.reporting.HistoryEntry;
import javax.inject.Inject;
+import org.joda.time.DateTime;
/**
* An EPP flow that deletes a host.
@@ -57,7 +58,7 @@ import javax.inject.Inject;
* @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException}
* @error {@link google.registry.flows.exceptions.ResourceToDeleteIsReferencedException}
*/
-public final class HostDeleteFlow extends Flow implements TransactionalFlow {
+public final class HostDeleteFlow implements TransactionalFlow {
private static final ImmutableSet DISALLOWED_STATUSES = ImmutableSet.of(
StatusValue.LINKED,
@@ -76,15 +77,18 @@ public final class HostDeleteFlow extends Flow implements TransactionalFlow {
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
+ @Inject @Superuser boolean isSuperuser;
@Inject HistoryEntry.Builder historyBuilder;
@Inject AsyncFlowEnqueuer asyncFlowEnqueuer;
+ @Inject EppResponse.Builder responseBuilder;
@Inject HostDeleteFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(MetadataExtension.class);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
+ DateTime now = ofy().getTransactionTime();
failfastForAsyncDelete(targetId, now, HostResource.class, GET_NAMESERVERS);
HostResource existingHost = loadAndVerifyExistence(HostResource.class, targetId, now);
verifyNoDisallowedStatuses(existingHost, DISALLOWED_STATUSES);
@@ -100,6 +104,6 @@ public final class HostDeleteFlow extends Flow implements TransactionalFlow {
.setModificationTime(now)
.setParent(Key.create(existingHost));
ofy().save().entities(newHost, historyBuilder.build());
- return createOutput(SUCCESS_WITH_ACTION_PENDING);
+ return responseBuilder.setResultFromCode(SUCCESS_WITH_ACTION_PENDING).build();
}
}
diff --git a/java/google/registry/flows/host/HostInfoFlow.java b/java/google/registry/flows/host/HostInfoFlow.java
index aedc4c094..bf1eb577b 100644
--- a/java/google/registry/flows/host/HostInfoFlow.java
+++ b/java/google/registry/flows/host/HostInfoFlow.java
@@ -18,7 +18,6 @@ import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
import static google.registry.model.EppResourceUtils.cloneResourceWithLinkedStatus;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import com.google.common.base.Optional;
import google.registry.flows.EppException;
@@ -27,9 +26,11 @@ import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.model.eppcommon.AuthInfo;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.host.HostResource;
+import google.registry.util.Clock;
import javax.inject.Inject;
+import org.joda.time.DateTime;
/**
* An EPP flow that returns information about a host.
@@ -39,20 +40,23 @@ import javax.inject.Inject;
*
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
*/
-public final class HostInfoFlow extends Flow {
+public final class HostInfoFlow implements Flow {
@Inject ExtensionManager extensionManager;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject Optional authInfo;
+ @Inject Clock clock;
+ @Inject EppResponse.Builder responseBuilder;
@Inject HostInfoFlow() {}
@Override
- public EppOutput run() throws EppException {
+ public EppResponse run() throws EppException {
extensionManager.validate(); // There are no legal extensions for this flow.
validateClientIsLoggedIn(clientId);
+ DateTime now = clock.nowUtc();
HostResource host = loadAndVerifyExistence(HostResource.class, targetId, now);
verifyOptionalAuthInfoForResource(authInfo, host);
- return createOutput(SUCCESS, cloneResourceWithLinkedStatus(host, now));
+ return responseBuilder.setResData(cloneResourceWithLinkedStatus(host, now)).build();
}
}
diff --git a/java/google/registry/flows/host/HostUpdateFlow.java b/java/google/registry/flows/host/HostUpdateFlow.java
index b54ce71ae..c3fa071d5 100644
--- a/java/google/registry/flows/host/HostUpdateFlow.java
+++ b/java/google/registry/flows/host/HostUpdateFlow.java
@@ -26,7 +26,6 @@ import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
import static google.registry.flows.host.HostFlowUtils.lookupSuperordinateDomain;
import static google.registry.flows.host.HostFlowUtils.validateHostName;
import static google.registry.flows.host.HostFlowUtils.verifyDomainIsSameRegistrar;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.index.ForeignKeyIndex.loadAndGetKey;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.util.CollectionUtils.isNullOrEmpty;
@@ -41,8 +40,8 @@ import google.registry.flows.EppException.ParameterValueRangeErrorException;
import google.registry.flows.EppException.RequiredParameterMissingException;
import google.registry.flows.EppException.StatusProhibitsOperationException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
+import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.async.AsyncFlowEnqueuer;
@@ -53,7 +52,7 @@ import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppinput.ResourceCommand;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.host.HostCommand.Update;
import google.registry.model.host.HostCommand.Update.AddRemove;
import google.registry.model.host.HostCommand.Update.Change;
@@ -62,6 +61,7 @@ import google.registry.model.index.ForeignKeyIndex;
import google.registry.model.reporting.HistoryEntry;
import java.util.Objects;
import javax.inject.Inject;
+import org.joda.time.DateTime;
/**
* An EPP flow that updates a host.
@@ -91,7 +91,7 @@ import javax.inject.Inject;
* @error {@link RenameHostToExternalRemoveIpException}
* @error {@link RenameHostToSubordinateRequiresIpException}
*/
-public final class HostUpdateFlow extends Flow implements TransactionalFlow {
+public final class HostUpdateFlow implements TransactionalFlow {
/**
* Note that CLIENT_UPDATE_PROHIBITED is intentionally not in this list. This is because it
@@ -107,19 +107,22 @@ public final class HostUpdateFlow extends Flow implements TransactionalFlow {
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
+ @Inject @Superuser boolean isSuperuser;
@Inject HistoryEntry.Builder historyBuilder;
@Inject AsyncFlowEnqueuer asyncFlowEnqueuer;
@Inject DnsQueue dnsQueue;
+ @Inject EppResponse.Builder responseBuilder;
@Inject HostUpdateFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.register(MetadataExtension.class);
extensionManager.validate();
validateClientIsLoggedIn(clientId);
Update command = (Update) resourceCommand;
Change change = command.getInnerChange();
String suppliedNewHostName = change.getFullyQualifiedHostName();
+ DateTime now = ofy().getTransactionTime();
HostResource existingHost = loadAndVerifyExistence(HostResource.class, targetId, now);
boolean isHostRename = suppliedNewHostName != null;
String oldHostName = targetId;
@@ -169,7 +172,7 @@ public final class HostUpdateFlow extends Flow implements TransactionalFlow {
.setParent(Key.create(existingHost))
.build());
ofy().save().entities(entitiesToSave.build());
- return createOutput(SUCCESS);
+ return responseBuilder.build();
}
private void verifyUpdateAllowed(
diff --git a/java/google/registry/flows/picker/FlowPicker.java b/java/google/registry/flows/picker/FlowPicker.java
index 5fa1b70fe..c5693c066 100644
--- a/java/google/registry/flows/picker/FlowPicker.java
+++ b/java/google/registry/flows/picker/FlowPicker.java
@@ -91,7 +91,7 @@ import java.util.Set;
public class FlowPicker {
/** Marker class for unimplemented flows. */
- private abstract static class UnimplementedFlow extends Flow {}
+ private abstract static class UnimplementedFlow implements Flow {}
/** A function type that takes an {@link EppInput} and returns a {@link Flow} class. */
private abstract static class FlowProvider {
diff --git a/java/google/registry/flows/poll/PollAckFlow.java b/java/google/registry/flows/poll/PollAckFlow.java
index 22bd3e042..161433cfb 100644
--- a/java/google/registry/flows/poll/PollAckFlow.java
+++ b/java/google/registry/flows/poll/PollAckFlow.java
@@ -17,7 +17,6 @@ package google.registry.flows.poll;
import static com.google.common.base.Preconditions.checkState;
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.poll.PollFlowUtils.getPollMessagesQuery;
-import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_NO_MESSAGES;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.util.DateTimeUtils.isBeforeOrAt;
@@ -30,11 +29,10 @@ import google.registry.flows.EppException.ObjectDoesNotExistException;
import google.registry.flows.EppException.ParameterValueSyntaxErrorException;
import google.registry.flows.EppException.RequiredParameterMissingException;
import google.registry.flows.ExtensionManager;
-import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.PollMessageId;
import google.registry.flows.TransactionalFlow;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.poll.MessageQueueInfo;
import google.registry.model.poll.PollMessage;
import google.registry.model.poll.PollMessageExternalKeyConverter;
@@ -55,15 +53,16 @@ import org.joda.time.DateTime;
* @error {@link PollAckFlow.MissingMessageIdException}
* @error {@link PollAckFlow.NotAuthorizedToAckMessageException}
*/
-public class PollAckFlow extends Flow implements TransactionalFlow {
+public class PollAckFlow implements TransactionalFlow {
@Inject ExtensionManager extensionManager;
@Inject @ClientId String clientId;
@Inject @PollMessageId String messageId;
+ @Inject EppResponse.Builder responseBuilder;
@Inject PollAckFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.validate(); // There are no legal extensions for this flow.
validateClientIsLoggedIn(clientId);
if (messageId.isEmpty()) {
@@ -78,6 +77,8 @@ public class PollAckFlow extends Flow implements TransactionalFlow {
throw new InvalidMessageIdException(messageId);
}
+ final DateTime now = ofy().getTransactionTime();
+
// Load the message to be acked. If a message is queued to be delivered in the future, we treat
// it as if it doesn't exist yet.
PollMessage pollMessage = ofy().load().key(pollMessageKey).now();
@@ -128,17 +129,14 @@ public class PollAckFlow extends Flow implements TransactionalFlow {
messageCount--;
}
if (messageCount <= 0) {
- return createOutput(SUCCESS_WITH_NO_MESSAGES);
+ return responseBuilder.setResultFromCode(SUCCESS_WITH_NO_MESSAGES).build();
}
- return createOutput(
- SUCCESS,
- null, // responseData
- null, // responseExtensions
- MessageQueueInfo.create(
- null, // eventTime
- null, // msg
- messageCount,
- messageId));
+ return responseBuilder
+ .setMessageQueueInfo(new MessageQueueInfo.Builder()
+ .setQueueLength(messageCount)
+ .setMessageId(messageId)
+ .build())
+ .build();
}
/** Registrar is not authorized to ack this message. */
diff --git a/java/google/registry/flows/poll/PollRequestFlow.java b/java/google/registry/flows/poll/PollRequestFlow.java
index 74d2e2699..822b20e38 100644
--- a/java/google/registry/flows/poll/PollRequestFlow.java
+++ b/java/google/registry/flows/poll/PollRequestFlow.java
@@ -27,11 +27,13 @@ import google.registry.flows.ExtensionManager;
import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.PollMessageId;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.poll.MessageQueueInfo;
import google.registry.model.poll.PollMessage;
import google.registry.model.poll.PollMessageExternalKeyConverter;
+import google.registry.util.Clock;
import javax.inject.Inject;
+import org.joda.time.DateTime;
/**
* An EPP flow for requesting {@link PollMessage}s.
@@ -44,34 +46,39 @@ import javax.inject.Inject;
*
* @error {@link PollRequestFlow.UnexpectedMessageIdException}
*/
-public class PollRequestFlow extends Flow {
+public class PollRequestFlow implements Flow {
@Inject ExtensionManager extensionManager;
@Inject @ClientId String clientId;
@Inject @PollMessageId String messageId;
+ @Inject Clock clock;
+ @Inject EppResponse.Builder responseBuilder;
@Inject PollRequestFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.validate(); // There are no legal extensions for this flow.
validateClientIsLoggedIn(clientId);
if (!messageId.isEmpty()) {
throw new UnexpectedMessageIdException();
}
// Return the oldest message from the queue.
+ DateTime now = clock.nowUtc();
PollMessage pollMessage = getPollMessagesQuery(clientId, now).first().now();
if (pollMessage == null) {
- return createOutput(SUCCESS_WITH_NO_MESSAGES);
+ return responseBuilder.setResultFromCode(SUCCESS_WITH_NO_MESSAGES).build();
}
- return createOutput(
- SUCCESS_WITH_ACK_MESSAGE,
- forceEmptyToNull(pollMessage.getResponseData()),
- forceEmptyToNull(pollMessage.getResponseExtensions()),
- MessageQueueInfo.create(
- pollMessage.getEventTime(),
- pollMessage.getMsg(),
- getPollMessagesQuery(clientId, now).count(),
- PollMessage.EXTERNAL_KEY_CONVERTER.convert(Key.create(pollMessage))));
+ return responseBuilder
+ .setResultFromCode(SUCCESS_WITH_ACK_MESSAGE)
+ .setMessageQueueInfo(new MessageQueueInfo.Builder()
+ .setQueueDate(pollMessage.getEventTime())
+ .setMsg(pollMessage.getMsg())
+ .setQueueLength(getPollMessagesQuery(clientId, now).count())
+ .setMessageId(PollMessage.EXTERNAL_KEY_CONVERTER.convert(Key.create(pollMessage)))
+ .build())
+ .setMultipleResData(forceEmptyToNull(pollMessage.getResponseData()))
+ .setExtensions(forceEmptyToNull(pollMessage.getResponseExtensions()))
+ .build();
}
/** Unexpected message id. */
diff --git a/java/google/registry/flows/session/HelloFlow.java b/java/google/registry/flows/session/HelloFlow.java
index e6ae67e01..78662ffd8 100644
--- a/java/google/registry/flows/session/HelloFlow.java
+++ b/java/google/registry/flows/session/HelloFlow.java
@@ -17,19 +17,20 @@ package google.registry.flows.session;
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.Flow;
-import google.registry.model.eppoutput.EppOutput;
import google.registry.model.eppoutput.Greeting;
+import google.registry.util.Clock;
import javax.inject.Inject;
/** A flow for an Epp "hello". */
-public class HelloFlow extends Flow {
+public class HelloFlow implements Flow {
@Inject ExtensionManager extensionManager;
+ @Inject Clock clock;
@Inject HelloFlow() {}
@Override
- public EppOutput run() throws EppException {
+ public Greeting run() throws EppException {
extensionManager.validate(); // There are no legal extensions for this flow.
- return EppOutput.create(Greeting.create(now));
+ return Greeting.create(clock.nowUtc());
}
}
diff --git a/java/google/registry/flows/session/LoginFlow.java b/java/google/registry/flows/session/LoginFlow.java
index 6cdd17f4d..86a9a5c28 100644
--- a/java/google/registry/flows/session/LoginFlow.java
+++ b/java/google/registry/flows/session/LoginFlow.java
@@ -30,13 +30,15 @@ import google.registry.flows.EppException.UnimplementedOptionException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
+import google.registry.flows.SessionMetadata;
+import google.registry.flows.TransportCredentials;
import google.registry.model.eppcommon.ProtocolDefinition;
import google.registry.model.eppcommon.ProtocolDefinition.ServiceExtension;
+import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.EppInput.Login;
import google.registry.model.eppinput.EppInput.Options;
import google.registry.model.eppinput.EppInput.Services;
-import google.registry.model.eppoutput.EppOutput;
-import google.registry.model.eppoutput.Result.Code;
+import google.registry.model.eppoutput.EppResponse;
import google.registry.model.registrar.Registrar;
import google.registry.util.FormattingLogger;
import java.util.Set;
@@ -62,7 +64,7 @@ import javax.inject.Inject;
* @error {@link LoginFlow.RegistrarAccountNotActiveException}
* @error {@link LoginFlow.UnsupportedLanguageException}
*/
-public class LoginFlow extends Flow {
+public class LoginFlow implements Flow {
private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass();
@@ -70,12 +72,16 @@ public class LoginFlow extends Flow {
private static final int MAX_FAILED_LOGIN_ATTEMPTS_PER_CONNECTION = 3;
@Inject ExtensionManager extensionManager;
+ @Inject EppInput eppInput;
+ @Inject SessionMetadata sessionMetadata;
+ @Inject TransportCredentials credentials;
@Inject @ClientId String clientId;
+ @Inject EppResponse.Builder responseBuilder;
@Inject LoginFlow() {}
/** Run the flow and log errors. */
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
try {
return runWithoutLogging();
} catch (EppException e) {
@@ -85,7 +91,7 @@ public class LoginFlow extends Flow {
}
/** Run the flow without bothering to log errors. The {@link #run} method will do that for us. */
- public final EppOutput runWithoutLogging() throws EppException {
+ public final EppResponse runWithoutLogging() throws EppException {
extensionManager.validate(); // There are no legal extensions for this flow.
Login login = (Login) eppInput.getCommandWrapper().getCommand();
if (!clientId.isEmpty()) {
@@ -137,7 +143,7 @@ public class LoginFlow extends Flow {
sessionMetadata.resetFailedLoginAttempts();
sessionMetadata.setClientId(login.getClientId());
sessionMetadata.setServiceExtensionUris(serviceExtensionUrisBuilder.build());
- return createOutput(Code.SUCCESS);
+ return responseBuilder.build();
}
/** Registrar with this client ID could not be found. */
diff --git a/java/google/registry/flows/session/LogoutFlow.java b/java/google/registry/flows/session/LogoutFlow.java
index bb38188fb..4cb622311 100644
--- a/java/google/registry/flows/session/LogoutFlow.java
+++ b/java/google/registry/flows/session/LogoutFlow.java
@@ -21,7 +21,8 @@ import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
-import google.registry.model.eppoutput.EppOutput;
+import google.registry.flows.SessionMetadata;
+import google.registry.model.eppoutput.EppResponse;
import javax.inject.Inject;
/**
@@ -29,17 +30,19 @@ import javax.inject.Inject;
*
* @error {@link google.registry.flows.FlowUtils.NotLoggedInException}
*/
-public class LogoutFlow extends Flow {
+public class LogoutFlow implements Flow {
@Inject ExtensionManager extensionManager;
@Inject @ClientId String clientId;
+ @Inject SessionMetadata sessionMetadata;
+ @Inject EppResponse.Builder responseBuilder;
@Inject LogoutFlow() {}
@Override
- public final EppOutput run() throws EppException {
+ public final EppResponse run() throws EppException {
extensionManager.validate(); // There are no legal extensions for this flow.
validateClientIsLoggedIn(clientId);
sessionMetadata.invalidate();
- return createOutput(SUCCESS_AND_CLOSE);
+ return responseBuilder.setResultFromCode(SUCCESS_AND_CLOSE).build();
}
}
diff --git a/java/google/registry/model/eppoutput/EppResponse.java b/java/google/registry/model/eppoutput/EppResponse.java
index a678f1954..9ed84c4a6 100644
--- a/java/google/registry/model/eppoutput/EppResponse.java
+++ b/java/google/registry/model/eppoutput/EppResponse.java
@@ -197,6 +197,10 @@ public class EppResponse extends ImmutableObject implements ResponseOrGreeting {
return this;
}
+ public Builder setResultFromCode(Result.Code resultCode) {
+ return setResult(Result.create(resultCode));
+ }
+
public Builder setResult(Result result) {
getInstance().result = result;
return this;
@@ -207,11 +211,19 @@ public class EppResponse extends ImmutableObject implements ResponseOrGreeting {
return this;
}
- public Builder setResData(@Nullable ImmutableList extends ResponseData> resData) {
+ public Builder setResData(ResponseData onlyResData) {
+ return setMultipleResData(ImmutableList.of(onlyResData));
+ }
+
+ public Builder setMultipleResData(@Nullable ImmutableList extends ResponseData> resData) {
getInstance().resData = resData;
return this;
}
+ public Builder setOnlyExtension(ResponseExtension onlyExtension) {
+ return setExtensions(ImmutableList.of(onlyExtension));
+ }
+
public Builder setExtensions(@Nullable ImmutableList extends ResponseExtension> extensions) {
getInstance().extensions = extensions;
return this;
diff --git a/java/google/registry/model/poll/MessageQueueInfo.java b/java/google/registry/model/poll/MessageQueueInfo.java
index 06d7bf5c9..5103a96da 100644
--- a/java/google/registry/model/poll/MessageQueueInfo.java
+++ b/java/google/registry/model/poll/MessageQueueInfo.java
@@ -14,10 +14,11 @@
package google.registry.model.poll;
+import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
+import google.registry.model.Buildable;
import google.registry.model.ImmutableObject;
-import javax.annotation.Nullable;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import org.joda.time.DateTime;
@@ -40,32 +41,34 @@ public class MessageQueueInfo extends ImmutableObject {
@XmlAttribute(name = "id")
String messageId;
- public DateTime getQueueDate() {
- return queueDate;
- }
+ /** A builder for constructing a {@link MessageQueueInfo}, since it's immutable. */
+ public static class Builder extends Buildable.Builder {
+ public Builder setQueueDate(DateTime queueDate) {
+ getInstance().queueDate = queueDate;
+ return this;
+ }
- public String getMsg() {
- return msg;
- }
+ public Builder setMsg(String msg) {
+ getInstance().msg = msg;
+ return this;
+ }
- public Integer getQueueLength() {
- return queueLength;
- }
+ public Builder setQueueLength(int queueLength) {
+ checkArgument(queueLength >= 0);
+ getInstance().queueLength = queueLength;
+ return this;
+ }
- public String getMessageId() {
- return messageId;
- }
+ public Builder setMessageId(String messageId) {
+ getInstance().messageId = messageId;
+ return this;
+ }
- public static MessageQueueInfo create(
- @Nullable DateTime queueDate,
- @Nullable String msg,
- Integer queueLength,
- String messageId) {
- MessageQueueInfo instance = new MessageQueueInfo();
- instance.queueDate = queueDate;
- instance.msg = msg;
- instance.queueLength = checkNotNull(queueLength);
- instance.messageId = checkNotNull(messageId);
- return instance;
+ @Override
+ public MessageQueueInfo build() {
+ checkNotNull(getInstance().messageId);
+ checkNotNull(getInstance().queueLength);
+ return super.build();
+ }
}
}
diff --git a/javatests/google/registry/flows/FlowRunnerTest.java b/javatests/google/registry/flows/FlowRunnerTest.java
index 25b7ea00d..787d14717 100644
--- a/javatests/google/registry/flows/FlowRunnerTest.java
+++ b/javatests/google/registry/flows/FlowRunnerTest.java
@@ -19,7 +19,6 @@ import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.TestDataHelper.loadFileWithSubstitutions;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
import com.google.appengine.api.users.User;
import com.google.common.base.Joiner;
@@ -31,8 +30,6 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.testing.TestLogHandler;
import google.registry.model.eppcommon.Trid;
-import google.registry.model.eppinput.EppInput;
-import google.registry.model.eppoutput.EppOutput;
import google.registry.model.eppoutput.EppResponse;
import google.registry.monitoring.whitebox.EppMetric;
import google.registry.testing.AppEngineRule;
@@ -66,27 +63,23 @@ public class FlowRunnerTest extends ShardableTestCase {
public void before() {
Logger.getLogger(FlowRunner.class.getCanonicalName()).addHandler(handler);
- final EppOutput eppOutput = mock(EppOutput.class);
- EppResponse eppResponse = mock(EppResponse.class);
- when(eppOutput.getResponse()).thenReturn(eppResponse);
+ final EppResponse eppResponse = mock(EppResponse.class);
flowRunner.clientId = "TheRegistrar";
- flowRunner.clock = new FakeClock();
flowRunner.credentials = new PasswordOnlyTransportCredentials();
- flowRunner.eppInput = new EppInput();
flowRunner.eppRequestSource = EppRequestSource.UNIT_TEST;
flowRunner.flowProvider =
Providers.of(
new Flow() {
@Override
- protected EppOutput run() {
- return eppOutput;
+ public EppResponse run() {
+ return eppResponse;
}});
flowRunner.inputXmlBytes = " ".getBytes(UTF_8);
flowRunner.isDryRun = false;
flowRunner.isSuperuser = false;
flowRunner.isTransactional = false;
- flowRunner.metric = EppMetric.builderForRequest("request-id-1", flowRunner.clock);
+ flowRunner.metric = EppMetric.builderForRequest("request-id-1", new FakeClock());
flowRunner.sessionMetadata =
new StatelessRequestSessionMetadata("TheRegistrar", ImmutableSet.of());
flowRunner.trid = Trid.create("client-123", "server-456");
diff --git a/javatests/google/registry/model/domain/DomainResourceTest.java b/javatests/google/registry/model/domain/DomainResourceTest.java
index 3d7bfd4bd..89d3d8549 100644
--- a/javatests/google/registry/model/domain/DomainResourceTest.java
+++ b/javatests/google/registry/model/domain/DomainResourceTest.java
@@ -52,7 +52,6 @@ import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppcommon.Trid;
import google.registry.model.eppoutput.EppOutput;
import google.registry.model.eppoutput.EppResponse;
-import google.registry.model.eppoutput.Result;
import google.registry.model.eppoutput.Result.Code;
import google.registry.model.host.HostResource;
import google.registry.model.ofy.RequestCapturingAsyncDatastoreService;
@@ -443,8 +442,8 @@ public class DomainResourceTest extends EntityTestCase {
int numPreviousReads = RequestCapturingAsyncDatastoreService.getReads().size();
EppXmlTransformer.marshal(
EppOutput.create(new EppResponse.Builder()
- .setResult(Result.create(Code.SUCCESS))
- .setResData(ImmutableList.of(domain))
+ .setResultFromCode(Code.SUCCESS)
+ .setResData(domain)
.setTrid(Trid.create(null, "abc"))
.build()),
ValidationMode.STRICT);
diff --git a/javatests/google/registry/model/poll/MessageQueueInfoTest.java b/javatests/google/registry/model/poll/MessageQueueInfoTest.java
deleted file mode 100644
index 5dd2a4397..000000000
--- a/javatests/google/registry/model/poll/MessageQueueInfoTest.java
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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.model.poll;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.common.testing.NullPointerTester;
-import com.google.common.testing.NullPointerTester.Visibility;
-import org.joda.time.DateTime;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Unit tests for {@link MessageQueueInfo}. */
-@RunWith(JUnit4.class)
-public final class MessageQueueInfoTest {
-
- @Test
- public void testDeadCodeWeDontWantToDelete() throws Exception {
- MessageQueueInfo mp = new MessageQueueInfo();
- mp.queueDate = DateTime.parse("1984-12-18TZ");
- assertThat(mp.getQueueDate()).isEqualTo(DateTime.parse("1984-12-18TZ"));
- mp.msg = "sloth";
- assertThat(mp.getMsg()).isEqualTo("sloth");
- mp.queueLength = 123;
- assertThat(mp.getQueueLength()).isEqualTo(123);
- mp.messageId = "adorable";
- assertThat(mp.getMessageId()).isEqualTo("adorable");
- }
-
- @Test
- public void testNullness() {
- NullPointerTester tester = new NullPointerTester();
- tester.testStaticMethods(MessageQueueInfo.class, Visibility.PROTECTED);
- }
-}
diff --git a/javatests/google/registry/model/translators/StatusValueAdapterTest.java b/javatests/google/registry/model/translators/StatusValueAdapterTest.java
index 03aba0ebc..3a9685a50 100644
--- a/javatests/google/registry/model/translators/StatusValueAdapterTest.java
+++ b/javatests/google/registry/model/translators/StatusValueAdapterTest.java
@@ -17,7 +17,6 @@ package google.registry.model.translators;
import static com.google.common.truth.Truth.assertThat;
import static java.nio.charset.StandardCharsets.UTF_8;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import google.registry.flows.EppXmlTransformer;
import google.registry.model.eppcommon.StatusValue;
@@ -51,9 +50,9 @@ public class StatusValueAdapterTest {
String marshalled = new String(
EppXmlTransformer.marshal(
EppOutput.create(new EppResponse.Builder()
- .setResData(ImmutableList.of(new HostResource.Builder()
+ .setResData(new HostResource.Builder()
.addStatusValue(StatusValue.CLIENT_UPDATE_PROHIBITED)
- .build()))
+ .build())
.build()),
ValidationMode.LENIENT),
UTF_8);