Replace command.applyTo() with inlined builder operations

These are much easier to understand.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=137446273
This commit is contained in:
cgoldfeder 2016-10-27 15:03:48 -07:00 committed by Ben McIlwain
parent b84d7f1fb5
commit 1dbc5f6bb0
28 changed files with 489 additions and 426 deletions

View file

@ -15,6 +15,7 @@
package google.registry.flows;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Sets.intersection;
import static google.registry.model.EppResourceUtils.loadByForeignKey;
import static google.registry.model.EppResourceUtils.queryDomainsUsingResource;
import static google.registry.model.domain.DomainResource.extendRegistrationWithCap;
@ -33,6 +34,8 @@ import com.googlecode.objectify.Work;
import google.registry.flows.EppException.AuthorizationErrorException;
import google.registry.flows.EppException.InvalidAuthorizationInformationErrorException;
import google.registry.flows.EppException.ObjectDoesNotExistException;
import google.registry.flows.EppException.ParameterValuePolicyErrorException;
import google.registry.flows.EppException.ParameterValueRangeErrorException;
import google.registry.flows.exceptions.MissingTransferRequestAuthInfoException;
import google.registry.flows.exceptions.NotPendingTransferException;
import google.registry.flows.exceptions.NotTransferInitiatorException;
@ -359,6 +362,25 @@ public final class ResourceFlowUtils {
}
}
/** Check that the same values aren't being added and removed in an update command. */
public static void checkSameValuesNotAddedAndRemoved(
ImmutableSet<?> fieldsToAdd, ImmutableSet<?> fieldsToRemove)
throws AddRemoveSameValueException {
if (!intersection(fieldsToAdd, fieldsToRemove).isEmpty()) {
throw new AddRemoveSameValueException();
}
}
/** Check that all {@link StatusValue} objects in a set are client-settable. */
public static void verifyAllStatusesAreClientSettable(Set<StatusValue> statusValues)
throws StatusNotClientSettableException {
for (StatusValue statusValue : statusValues) {
if (!statusValue.isClientSettable()) {
throw new StatusNotClientSettableException(statusValue.getXmlName());
}
}
}
/** Resource with this id does not exist. */
public static class ResourceDoesNotExistException extends ObjectDoesNotExistException {
public ResourceDoesNotExistException(Class<?> type, String targetId) {
@ -380,4 +402,18 @@ public final class ResourceFlowUtils {
super("Authorization information for accessing resource is invalid");
}
}
/** Cannot add and remove the same value. */
public static class AddRemoveSameValueException extends ParameterValuePolicyErrorException {
public AddRemoveSameValueException() {
super("Cannot add and remove the same value");
}
}
/** The specified status value cannot be set by clients. */
public static class StatusNotClientSettableException extends ParameterValueRangeErrorException {
public StatusNotClientSettableException(String statusValue) {
super(String.format("Status value %s cannot be set by clients", statusValue));
}
}
}

View file

@ -65,12 +65,18 @@ public final class ContactCreateFlow extends Flow implements TransactionalFlow {
validateClientIsLoggedIn(clientId);
Create command = (Create) resourceCommand;
verifyResourceDoesNotExist(ContactResource.class, targetId, now);
Builder builder = new Builder();
command.applyTo(builder);
ContactResource newContact = builder
ContactResource newContact = new Builder()
.setContactId(targetId)
.setAuthInfo(command.getAuthInfo())
.setCreationClientId(clientId)
.setCurrentSponsorClientId(clientId)
.setRepoId(createContactHostRoid(ObjectifyService.allocateId()))
.setFaxNumber(command.getFax())
.setVoiceNumber(command.getVoice())
.setDisclose(command.getDisclose())
.setEmailAddress(command.getEmail())
.setInternationalizedPostalInfo(command.getInternationalizedPostalInfo())
.setLocalizedPostalInfo(command.getLocalizedPostalInfo())
.build();
validateAsciiPostalInfo(newContact.getInternationalizedPostalInfo());
validateContactAgainstPolicy(newContact);

View file

@ -14,8 +14,11 @@
package google.registry.flows.contact;
import static com.google.common.collect.Sets.union;
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.checkSameValuesNotAddedAndRemoved;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyAllStatusesAreClientSettable;
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
@ -26,7 +29,6 @@ import static google.registry.model.ofy.ObjectifyService.ofy;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager;
@ -34,30 +36,30 @@ import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.exceptions.AddRemoveSameValueEppException;
import google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException;
import google.registry.flows.exceptions.StatusNotClientSettableException;
import google.registry.model.contact.ContactCommand.Update;
import google.registry.model.contact.ContactCommand.Update.Change;
import google.registry.model.contact.ContactResource;
import google.registry.model.contact.ContactResource.Builder;
import google.registry.model.contact.PostalInfo;
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.eppinput.ResourceCommand.AddRemoveSameValueException;
import google.registry.model.eppoutput.EppOutput;
import google.registry.model.reporting.HistoryEntry;
import javax.annotation.Nullable;
import javax.inject.Inject;
/**
* An EPP flow that updates a contact.
*
* @error {@link google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}
* @error {@link google.registry.flows.exceptions.AddRemoveSameValueEppException}
* @error {@link google.registry.flows.ResourceFlowUtils.StatusNotClientSettableException}
* @error {@link google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException}
* @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException}
* @error {@link google.registry.flows.exceptions.StatusNotClientSettableException}
* @error {@link ContactFlowUtils.BadInternationalizedPostalInfoException}
* @error {@link ContactFlowUtils.DeclineContactDisclosureFieldDisallowedPolicyException}
*/
@ -88,15 +90,11 @@ public final class ContactUpdateFlow extends Flow implements TransactionalFlow {
Update command = (Update) resourceCommand;
ContactResource existingContact = loadAndVerifyExistence(ContactResource.class, targetId, now);
verifyOptionalAuthInfoForResource(authInfo, existingContact);
if (!isSuperuser) {
ImmutableSet<StatusValue> statusToRemove = command.getInnerRemove().getStatusValues();
ImmutableSet<StatusValue> statusesToAdd = command.getInnerAdd().getStatusValues();
if (!isSuperuser) { // The superuser can update any contact and set any status.
verifyResourceOwnership(clientId, existingContact);
}
for (StatusValue statusValue : Sets.union(
command.getInnerAdd().getStatusValues(),
command.getInnerRemove().getStatusValues())) {
if (!isSuperuser && !statusValue.isClientSettable()) { // The superuser can set any status.
throw new StatusNotClientSettableException(statusValue.getXmlName());
}
verifyAllStatusesAreClientSettable(union(statusesToAdd, statusToRemove));
}
verifyNoDisallowedStatuses(existingContact, DISALLOWED_STATUSES);
historyBuilder
@ -104,15 +102,39 @@ public final class ContactUpdateFlow extends Flow implements TransactionalFlow {
.setModificationTime(now)
.setXmlBytes(null) // We don't want to store contact details in the history entry.
.setParent(Key.create(existingContact));
checkSameValuesNotAddedAndRemoved(statusesToAdd, statusToRemove);
Builder builder = existingContact.asBuilder();
try {
command.applyTo(builder);
} catch (AddRemoveSameValueException e) {
throw new AddRemoveSameValueEppException();
Change change = command.getInnerChange();
// The spec requires the following behaviors:
// * If you update part of a postal info, the fields that you didn't update are unchanged.
// * If you update one postal info but not the other, the other is deleted.
// Therefore, if you want to preserve one postal info and update another you need to send the
// update and also something that technically updates the preserved one, even if it only
// "updates" it by setting just one field to the same value.
PostalInfo internationalized = change.getInternationalizedPostalInfo();
PostalInfo localized = change.getLocalizedPostalInfo();
if (internationalized != null) {
builder.overlayInternationalizedPostalInfo(internationalized);
if (localized == null) {
builder.setLocalizedPostalInfo(null);
}
}
if (localized != null) {
builder.overlayLocalizedPostalInfo(localized);
if (internationalized == null) {
builder.setInternationalizedPostalInfo(null);
}
}
ContactResource newContact = builder
.setLastEppUpdateTime(now)
.setLastEppUpdateClientId(clientId)
.setAuthInfo(preferFirst(change.getAuthInfo(), existingContact.getAuthInfo()))
.setDisclose(preferFirst(change.getDisclose(), existingContact.getDisclose()))
.setEmailAddress(preferFirst(change.getEmail(), existingContact.getEmailAddress()))
.setFaxNumber(preferFirst(change.getFax(), existingContact.getFaxNumber()))
.setVoiceNumber(preferFirst(change.getVoice(), existingContact.getVoiceNumber()))
.addStatusValues(statusesToAdd)
.removeStatusValues(statusToRemove)
.build();
// If the resource is marked with clientUpdateProhibited, and this update did not clear that
// status, then the update must be disallowed (unless a superuser is requesting the change).
@ -126,4 +148,10 @@ public final class ContactUpdateFlow extends Flow implements TransactionalFlow {
ofy().save().<Object>entities(newContact, historyBuilder.build());
return createOutput(SUCCESS);
}
/** Return the first non-null param, or null if both are null. */
@Nullable
private static <T> T preferFirst(@Nullable T a, @Nullable T b) {
return a != null ? a : b;
}
}

View file

@ -146,9 +146,7 @@ public class DomainAllocateFlow extends Flow implements TransactionalFlow {
domainName, application, historyEntry, isSunrushAddGracePeriod, registry, years);
entitiesToSave.addAll(billsAndPolls);
DateTime registrationExpirationTime = leapSafeAddYears(now, years);
DomainResource.Builder domainBuilder = new DomainResource.Builder();
command.applyTo(domainBuilder);
DomainResource newDomain = domainBuilder
DomainResource newDomain = new DomainResource.Builder()
.setCreationClientId(clientId)
.setCurrentSponsorClientId(clientId)
.setRepoId(repoId)
@ -167,6 +165,11 @@ public class DomainAllocateFlow extends Flow implements TransactionalFlow {
.setStatusValues(ReservationType.NAME_COLLISION == getReservationType(domainName)
? ImmutableSet.of(StatusValue.SERVER_HOLD)
: ImmutableSet.<StatusValue>of())
.setRegistrant(command.getRegistrant())
.setAuthInfo(command.getAuthInfo())
.setFullyQualifiedDomainName(targetId)
.setNameservers(command.getNameservers())
.setContacts(command.getContacts())
.build();
entitiesToSave.add(
newDomain,

View file

@ -210,9 +210,7 @@ public final class DomainApplicationCreateFlow extends Flow implements Transacti
validateFeeChallenge(targetId, tld, now, feeCreate, commandOperations.getTotalCost());
SecDnsCreateExtension secDnsCreate =
validateSecDnsExtension(eppInput.getSingleExtension(SecDnsCreateExtension.class));
DomainApplication.Builder applicationBuilder = new DomainApplication.Builder();
command.applyTo(applicationBuilder);
applicationBuilder
DomainApplication newApplication = new DomainApplication.Builder()
.setCreationTrid(trid)
.setCreationClientId(clientId)
.setCurrentSponsorClientId(clientId)
@ -224,6 +222,11 @@ public final class DomainApplicationCreateFlow extends Flow implements Transacti
.setApplicationStatus(ApplicationStatus.VALIDATED)
.addStatusValue(StatusValue.PENDING_CREATE)
.setDsData(secDnsCreate == null ? null : secDnsCreate.getDsData())
.setRegistrant(command.getRegistrant())
.setAuthInfo(command.getAuthInfo())
.setFullyQualifiedDomainName(targetId)
.setNameservers(command.getNameservers())
.setContacts(command.getContacts())
.setEncodedSignedMarks(FluentIterable
.from(launchCreate.getSignedMarks())
.transform(new Function<AbstractSignedMark, EncodedSignedMark>() {
@ -231,8 +234,8 @@ public final class DomainApplicationCreateFlow extends Flow implements Transacti
public EncodedSignedMark apply(AbstractSignedMark abstractSignedMark) {
return (EncodedSignedMark) abstractSignedMark;
}})
.toList());
DomainApplication newApplication = applicationBuilder.build();
.toList())
.build();
HistoryEntry historyEntry = buildHistory(newApplication.getRepoId(), command.getPeriod());
ImmutableSet.Builder<ImmutableObject> entitiesToSave = new ImmutableSet.Builder<>();
handleExtraFlowLogic(

View file

@ -16,7 +16,11 @@ package google.registry.flows.domain;
import static com.google.common.base.CaseFormat.LOWER_CAMEL;
import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.collect.Sets.union;
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.checkSameValuesNotAddedAndRemoved;
import static google.registry.flows.ResourceFlowUtils.verifyAllStatusesAreClientSettable;
import static google.registry.flows.ResourceFlowUtils.verifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
@ -34,7 +38,6 @@ import static google.registry.flows.domain.DomainFlowUtils.validateRequiredConta
import static google.registry.flows.domain.DomainFlowUtils.verifyApplicationDomainMatchesTargetId;
import static google.registry.flows.domain.DomainFlowUtils.verifyClientUpdateNotProhibited;
import static google.registry.flows.domain.DomainFlowUtils.verifyNotInPendingDelete;
import static google.registry.flows.domain.DomainFlowUtils.verifyStatusChangesAreClientSettable;
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;
@ -52,11 +55,11 @@ import google.registry.flows.FlowModule.ApplicationId;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.exceptions.AddRemoveSameValueEppException;
import google.registry.model.ImmutableObject;
import google.registry.model.domain.DomainApplication;
import google.registry.model.domain.DomainApplication.Builder;
import google.registry.model.domain.DomainCommand.Update;
import google.registry.model.domain.DomainCommand.Update.AddRemove;
import google.registry.model.domain.DomainCommand.Update.Change;
import google.registry.model.domain.launch.ApplicationStatus;
import google.registry.model.domain.launch.LaunchUpdateExtension;
import google.registry.model.domain.metadata.MetadataExtension;
@ -64,7 +67,6 @@ import google.registry.model.domain.secdns.SecDnsUpdateExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppinput.ResourceCommand.AddRemoveSameValueException;
import google.registry.model.eppoutput.EppOutput;
import google.registry.model.reporting.HistoryEntry;
import javax.inject.Inject;
@ -76,12 +78,12 @@ import javax.inject.Inject;
* cannot change the domain name that is being applied for.
*
* @error {@link google.registry.flows.EppException.UnimplementedExtensionException}
* @error {@link google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}
* @error {@link google.registry.flows.exceptions.AddRemoveSameValueEppException}
* @error {@link google.registry.flows.ResourceFlowUtils.StatusNotClientSettableException}
* @error {@link google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException}
* @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException}
* @error {@link google.registry.flows.exceptions.StatusNotClientSettableException}
* @error {@link DomainFlowUtils.ApplicationDomainNameMismatchException}
* @error {@link DomainFlowUtils.DuplicateContactForRoleException}
* @error {@link DomainFlowUtils.EmptySecDnsUpdateException}
@ -151,10 +153,12 @@ public class DomainApplicationUpdateFlow extends Flow implements TransactionalFl
protected final void verifyUpdateAllowed(
DomainApplication existingApplication, Update command) throws EppException {
AddRemove add = command.getInnerAdd();
AddRemove remove = command.getInnerRemove();
if (!isSuperuser) {
verifyResourceOwnership(clientId, existingApplication);
verifyClientUpdateNotProhibited(command, existingApplication);
verifyStatusChangesAreClientSettable(command);
verifyAllStatusesAreClientSettable(union(add.getStatusValues(), remove.getStatusValues()));
}
String tld = existingApplication.getTld();
checkAllowedAccessToTld(clientId, tld);
@ -164,14 +168,14 @@ public class DomainApplicationUpdateFlow extends Flow implements TransactionalFl
existingApplication.getApplicationStatus());
}
verifyNotInPendingDelete(
command.getInnerAdd().getContacts(),
add.getContacts(),
command.getInnerChange().getRegistrant(),
command.getInnerAdd().getNameservers());
validateContactsHaveTypes(command.getInnerAdd().getContacts());
validateContactsHaveTypes(command.getInnerRemove().getContacts());
add.getNameservers());
validateContactsHaveTypes(add.getContacts());
validateContactsHaveTypes(remove.getContacts());
validateRegistrantAllowedOnTld(tld, command.getInnerChange().getRegistrantContactId());
validateNameserversAllowedOnTld(
tld, command.getInnerAdd().getNameserverFullyQualifiedHostNames());
tld, add.getNameserverFullyQualifiedHostNames());
}
private HistoryEntry buildHistory(DomainApplication existingApplication) {
@ -183,20 +187,30 @@ public class DomainApplicationUpdateFlow extends Flow implements TransactionalFl
}
private DomainApplication updateApplication(
DomainApplication existingApplication, Update command) throws EppException {
Builder builder = existingApplication.asBuilder();
try {
command.applyTo(builder);
} catch (AddRemoveSameValueException e) {
throw new AddRemoveSameValueEppException();
}
builder.setLastEppUpdateTime(now).setLastEppUpdateClientId(clientId);
// Handle the secDNS extension.
DomainApplication application, Update command) throws EppException {
AddRemove add = command.getInnerAdd();
AddRemove remove = command.getInnerRemove();
checkSameValuesNotAddedAndRemoved(add.getNameservers(), remove.getNameservers());
checkSameValuesNotAddedAndRemoved(add.getContacts(), remove.getContacts());
checkSameValuesNotAddedAndRemoved(add.getStatusValues(), remove.getStatusValues());
Change change = command.getInnerChange();
SecDnsUpdateExtension secDnsUpdate = eppInput.getSingleExtension(SecDnsUpdateExtension.class);
if (secDnsUpdate != null) {
builder.setDsData(updateDsData(existingApplication.getDsData(), secDnsUpdate));
}
return builder.build();
return application.asBuilder()
// Handle the secDNS extension.
.setDsData(secDnsUpdate != null
? updateDsData(application.getDsData(), secDnsUpdate)
: application.getDsData())
.setLastEppUpdateTime(now)
.setLastEppUpdateClientId(clientId)
.addStatusValues(add.getStatusValues())
.removeStatusValues(remove.getStatusValues())
.addNameservers(add.getNameservers())
.removeNameservers(remove.getNameservers())
.addContacts(add.getContacts())
.removeContacts(remove.getContacts())
.setRegistrant(firstNonNull(change.getRegistrant(), application.getRegistrant()))
.setAuthInfo(firstNonNull(change.getAuthInfo(), application.getAuthInfo()))
.build();
}
private void validateNewApplication(DomainApplication newApplication) throws EppException {

View file

@ -245,9 +245,7 @@ public class DomainCreateFlow extends Flow implements TransactionalFlow {
if (!commandOperations.getEapCost().isZero()) {
entitiesToSave.add(createEapBillingEvent(commandOperations, createBillingEvent));
}
DomainResource.Builder domainBuilder = new DomainResource.Builder();
command.applyTo(domainBuilder);
DomainResource newDomain = domainBuilder
DomainResource newDomain = new DomainResource.Builder()
.setCreationClientId(clientId)
.setCurrentSponsorClientId(clientId)
.setRepoId(repoId)
@ -261,6 +259,11 @@ public class DomainCreateFlow extends Flow implements TransactionalFlow {
? verifySignedMarks(launchCreate.getSignedMarks(), domainLabel, now).getId()
: null)
.setDsData(secDnsCreate == null ? null : secDnsCreate.getDsData())
.setRegistrant(command.getRegistrant())
.setAuthInfo(command.getAuthInfo())
.setFullyQualifiedDomainName(targetId)
.setNameservers(command.getNameservers())
.setContacts(command.getContacts())
.addGracePeriod(GracePeriod.forBillingEvent(GracePeriodStatus.ADD, createBillingEvent))
.build();
handleExtraFlowLogic(registry.getTldStr(), years, historyEntry, newDomain);

View file

@ -59,7 +59,6 @@ import google.registry.flows.EppException.UnimplementedOptionException;
import google.registry.flows.domain.TldSpecificLogicProxy.EppCommandOperations;
import google.registry.flows.exceptions.ResourceAlreadyExistsException;
import google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException;
import google.registry.flows.exceptions.StatusNotClientSettableException;
import google.registry.model.EppResource;
import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Flag;
@ -829,18 +828,6 @@ public class DomainFlowUtils {
return ImmutableSet.copyOf(union(difference(oldDsData, toRemove), toAdd));
}
/** Check that all of the status values added or removed in an update are client-settable. */
static void verifyStatusChangesAreClientSettable(Update command)
throws StatusNotClientSettableException {
for (StatusValue statusValue : union(
command.getInnerAdd().getStatusValues(),
command.getInnerRemove().getStatusValues())) {
if (!statusValue.isClientSettable()) {
throw new StatusNotClientSettableException(statusValue.getXmlName());
}
}
}
/** If a domain or application has "clientUpdateProhibited" set, updates must clear it or fail. */
static void verifyClientUpdateNotProhibited(Update command, DomainBase existingResource)
throws ResourceHasClientUpdateProhibitedException {

View file

@ -14,9 +14,13 @@
package google.registry.flows.domain;
import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.collect.Sets.symmetricDifference;
import static com.google.common.collect.Sets.union;
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.checkSameValuesNotAddedAndRemoved;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyAllStatusesAreClientSettable;
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
@ -33,7 +37,6 @@ import static google.registry.flows.domain.DomainFlowUtils.validateRegistrantAll
import static google.registry.flows.domain.DomainFlowUtils.validateRequiredContactsPresent;
import static google.registry.flows.domain.DomainFlowUtils.verifyClientUpdateNotProhibited;
import static google.registry.flows.domain.DomainFlowUtils.verifyNotInPendingDelete;
import static google.registry.flows.domain.DomainFlowUtils.verifyStatusChangesAreClientSettable;
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;
@ -52,11 +55,12 @@ import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.domain.DomainFlowUtils.FeesRequiredForNonFreeUpdateException;
import google.registry.flows.domain.TldSpecificLogicProxy.EppCommandOperations;
import google.registry.flows.exceptions.AddRemoveSameValueEppException;
import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.domain.DomainCommand.Update;
import google.registry.model.domain.DomainCommand.Update.AddRemove;
import google.registry.model.domain.DomainCommand.Update.Change;
import google.registry.model.domain.DomainResource;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.fee.FeeTransformCommandExtension;
@ -67,7 +71,6 @@ import google.registry.model.domain.secdns.SecDnsUpdateExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppinput.ResourceCommand.AddRemoveSameValueException;
import google.registry.model.eppoutput.EppOutput;
import google.registry.model.registry.Registry;
import google.registry.model.reporting.HistoryEntry;
@ -92,13 +95,13 @@ import org.joda.time.DateTime;
* accordingly.
*
* @error {@link google.registry.flows.EppException.UnimplementedExtensionException}
* @error {@link google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}
* @error {@link google.registry.flows.exceptions.AddRemoveSameValueEppException}
* @error {@link google.registry.flows.ResourceFlowUtils.StatusNotClientSettableException}
* @error {@link google.registry.flows.exceptions.OnlyToolCanPassMetadataException}
* @error {@link google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException}
* @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException}
* @error {@link google.registry.flows.exceptions.StatusNotClientSettableException}
* @error {@link DomainFlowUtils.DuplicateContactForRoleException}
* @error {@link DomainFlowUtils.EmptySecDnsUpdateException}
* @error {@link DomainFlowUtils.FeesMismatchException}
@ -181,10 +184,12 @@ public final class DomainUpdateFlow extends Flow implements TransactionalFlow {
throws EppException {
verifyNoDisallowedStatuses(existingDomain, UPDATE_DISALLOWED_STATUSES);
verifyOptionalAuthInfoForResource(authInfo, existingDomain);
AddRemove add = command.getInnerAdd();
AddRemove remove = command.getInnerRemove();
if (!isSuperuser) {
verifyResourceOwnership(clientId, existingDomain);
verifyClientUpdateNotProhibited(command, existingDomain);
verifyStatusChangesAreClientSettable(command);
verifyAllStatusesAreClientSettable(union(add.getStatusValues(), remove.getStatusValues()));
}
String tld = existingDomain.getTld();
checkAllowedAccessToTld(clientId, tld);
@ -204,14 +209,14 @@ public final class DomainUpdateFlow extends Flow implements TransactionalFlow {
throw new FeesRequiredForNonFreeUpdateException();
}
verifyNotInPendingDelete(
command.getInnerAdd().getContacts(),
add.getContacts(),
command.getInnerChange().getRegistrant(),
command.getInnerAdd().getNameservers());
validateContactsHaveTypes(command.getInnerAdd().getContacts());
validateContactsHaveTypes(command.getInnerRemove().getContacts());
add.getNameservers());
validateContactsHaveTypes(add.getContacts());
validateContactsHaveTypes(remove.getContacts());
validateRegistrantAllowedOnTld(tld, command.getInnerChange().getRegistrantContactId());
validateNameserversAllowedOnTld(
tld, command.getInnerAdd().getNameserverFullyQualifiedHostNames());
tld, add.getNameserverFullyQualifiedHostNames());
}
private HistoryEntry buildHistoryEntry(DomainResource existingDomain) {
@ -222,22 +227,31 @@ public final class DomainUpdateFlow extends Flow implements TransactionalFlow {
.build();
}
private DomainResource performUpdate(Update command, DomainResource existingDomain)
private DomainResource performUpdate(Update command, DomainResource domain)
throws EppException {
DomainResource.Builder builder = existingDomain.asBuilder()
.setLastEppUpdateTime(now)
.setLastEppUpdateClientId(clientId);
try {
command.applyTo(builder);
} catch (AddRemoveSameValueException e) {
throw new AddRemoveSameValueEppException();
}
// Handle the secDNS extension.
AddRemove add = command.getInnerAdd();
AddRemove remove = command.getInnerRemove();
checkSameValuesNotAddedAndRemoved(add.getNameservers(), remove.getNameservers());
checkSameValuesNotAddedAndRemoved(add.getContacts(), remove.getContacts());
checkSameValuesNotAddedAndRemoved(add.getStatusValues(), remove.getStatusValues());
Change change = command.getInnerChange();
SecDnsUpdateExtension secDnsUpdate = eppInput.getSingleExtension(SecDnsUpdateExtension.class);
if (secDnsUpdate != null) {
builder.setDsData(updateDsData(existingDomain.getDsData(), secDnsUpdate));
}
return builder.build();
return domain.asBuilder()
// Handle the secDNS extension.
.setDsData(secDnsUpdate != null
? updateDsData(domain.getDsData(), secDnsUpdate)
: domain.getDsData())
.setLastEppUpdateTime(now)
.setLastEppUpdateClientId(clientId)
.addStatusValues(add.getStatusValues())
.removeStatusValues(remove.getStatusValues())
.addNameservers(add.getNameservers())
.removeNameservers(remove.getNameservers())
.addContacts(add.getContacts())
.removeContacts(remove.getContacts())
.setRegistrant(firstNonNull(change.getRegistrant(), domain.getRegistrant()))
.setAuthInfo(firstNonNull(change.getAuthInfo(), domain.getAuthInfo()))
.build();
}
private DomainResource convertSunrushAddToAdd(

View file

@ -1,24 +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.flows.exceptions;
import google.registry.flows.EppException.ParameterValuePolicyErrorException;
/** Cannot add and remove the same value. */
public class AddRemoveSameValueEppException extends ParameterValuePolicyErrorException {
public AddRemoveSameValueEppException() {
super("Cannot add and remove the same value");
}
}

View file

@ -1,24 +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.flows.exceptions;
import google.registry.flows.EppException.ParameterValueRangeErrorException;
/** The specified status value cannot be set by clients. */
public class StatusNotClientSettableException extends ParameterValueRangeErrorException {
public StatusNotClientSettableException(String statusValue) {
super(String.format("Status value %s cannot be set by clients", statusValue));
}
}

View file

@ -101,11 +101,11 @@ public final class HostCreateFlow extends Flow implements TransactionalFlow {
? new SubordinateHostMustHaveIpException()
: new UnexpectedExternalHostIpException();
}
Builder builder = new Builder();
command.applyTo(builder);
HostResource newHost = builder
HostResource newHost = new Builder()
.setCreationClientId(clientId)
.setCurrentSponsorClientId(clientId)
.setFullyQualifiedHostName(targetId)
.setInetAddresses(command.getInetAddresses())
.setRepoId(createContactHostRoid(ObjectifyService.allocateId()))
.setSuperordinateDomain(
superordinateDomain.isPresent() ? Key.create(superordinateDomain.get()) : null)

View file

@ -15,8 +15,11 @@
package google.registry.flows.host;
import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.collect.Sets.union;
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.checkSameValuesNotAddedAndRemoved;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyAllStatusesAreClientSettable;
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
@ -30,7 +33,6 @@ import static google.registry.util.CollectionUtils.isNullOrEmpty;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.googlecode.objectify.Key;
import google.registry.dns.DnsQueue;
import google.registry.flows.EppException;
@ -44,20 +46,18 @@ import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.async.AsyncFlowEnqueuer;
import google.registry.flows.exceptions.AddRemoveSameValueEppException;
import google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException;
import google.registry.flows.exceptions.StatusNotClientSettableException;
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.eppcommon.StatusValue;
import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppinput.ResourceCommand.AddRemoveSameValueException;
import google.registry.model.eppoutput.EppOutput;
import google.registry.model.host.HostCommand.Update;
import google.registry.model.host.HostCommand.Update.AddRemove;
import google.registry.model.host.HostCommand.Update.Change;
import google.registry.model.host.HostResource;
import google.registry.model.host.HostResource.Builder;
import google.registry.model.index.ForeignKeyIndex;
import google.registry.model.reporting.HistoryEntry;
import java.util.Objects;
@ -76,11 +76,12 @@ import javax.inject.Inject;
* when it is renamed from external to internal at least one must be added. If the host is renamed
* or IP addresses are added, tasks are enqueued to update DNS accordingly.
*
* @error {@link google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}
* @error {@link google.registry.flows.ResourceFlowUtils.StatusNotClientSettableException}
* @error {@link google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException}
* @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException}
* @error {@link google.registry.flows.exceptions.StatusNotClientSettableException}
* @error {@link HostFlowUtils.HostNameTooShallowException}
* @error {@link HostFlowUtils.InvalidHostNameException}
* @error {@link HostFlowUtils.SuperordinateDomainDoesNotExistException}
@ -117,7 +118,8 @@ public final class HostUpdateFlow extends Flow implements TransactionalFlow {
extensionManager.validate();
validateClientIsLoggedIn(clientId);
Update command = (Update) resourceCommand;
String suppliedNewHostName = command.getInnerChange().getFullyQualifiedHostName();
Change change = command.getInnerChange();
String suppliedNewHostName = change.getFullyQualifiedHostName();
HostResource existingHost = loadAndVerifyExistence(HostResource.class, targetId, now);
boolean isHostRename = suppliedNewHostName != null;
String oldHostName = targetId;
@ -128,13 +130,16 @@ public final class HostUpdateFlow extends Flow implements TransactionalFlow {
if (isHostRename && loadAndGetKey(HostResource.class, newHostName, now) != null) {
throw new HostAlreadyExistsException(newHostName);
}
Builder builder = existingHost.asBuilder();
try {
command.applyTo(builder);
} catch (AddRemoveSameValueException e) {
throw new AddRemoveSameValueEppException();
}
builder
AddRemove add = command.getInnerAdd();
AddRemove remove = command.getInnerRemove();
checkSameValuesNotAddedAndRemoved(add.getStatusValues(), remove.getStatusValues());
checkSameValuesNotAddedAndRemoved(add.getInetAddresses(), remove.getInetAddresses());
HostResource newHost = existingHost.asBuilder()
.setFullyQualifiedHostName(newHostName)
.addStatusValues(add.getStatusValues())
.removeStatusValues(remove.getStatusValues())
.addInetAddresses(add.getInetAddresses())
.removeInetAddresses(remove.getInetAddresses())
.setLastEppUpdateTime(now)
.setLastEppUpdateClientId(clientId)
// The superordinateDomain can be missing if the new name is external.
@ -142,9 +147,10 @@ public final class HostUpdateFlow extends Flow implements TransactionalFlow {
// the lookupSuperordinateDomain(...) call above, so that it will never be stale.
.setSuperordinateDomain(
superordinateDomain.isPresent() ? Key.create(superordinateDomain.get()) : null)
.setLastSuperordinateChange(superordinateDomain == null ? null : now);
// Rely on the host's cloneProjectedAtTime() method to handle setting of transfer data.
HostResource newHost = builder.build().cloneProjectedAtTime(now);
.setLastSuperordinateChange(superordinateDomain == null ? null : now)
.build()
// Rely on the host's cloneProjectedAtTime() method to handle setting of transfer data.
.cloneProjectedAtTime(now);
verifyHasIpsIffIsExternal(command, existingHost, newHost);
ImmutableSet.Builder<ImmutableObject> entitiesToSave = new ImmutableSet.Builder<>();
entitiesToSave.add(newHost);
@ -172,21 +178,16 @@ public final class HostUpdateFlow extends Flow implements TransactionalFlow {
verifyOptionalAuthInfoForResource(authInfo, existingResource);
if (!isSuperuser) {
verifyResourceOwnership(clientId, existingResource);
ImmutableSet<StatusValue> statusesToAdd = command.getInnerAdd().getStatusValues();
ImmutableSet<StatusValue> statusesToRemove = command.getInnerRemove().getStatusValues();
// If the resource is marked with clientUpdateProhibited, and this update does not clear that
// status, then the update must be disallowed (unless a superuser is requesting the change).
if (!isSuperuser
&& existingResource.getStatusValues().contains(StatusValue.CLIENT_UPDATE_PROHIBITED)
&& !command.getInnerRemove().getStatusValues()
.contains(StatusValue.CLIENT_UPDATE_PROHIBITED)) {
&& !statusesToRemove.contains(StatusValue.CLIENT_UPDATE_PROHIBITED)) {
throw new ResourceHasClientUpdateProhibitedException();
}
}
for (StatusValue statusValue : Sets.union(
command.getInnerAdd().getStatusValues(),
command.getInnerRemove().getStatusValues())) {
if (!isSuperuser && !statusValue.isClientSettable()) { // The superuser can set any status.
throw new StatusNotClientSettableException(statusValue.getXmlName());
}
verifyAllStatusesAreClientSettable(union(statusesToAdd, statusesToRemove));
}
verifyDomainIsSameRegistrar(superordinateDomain, clientId);
verifyNoDisallowedStatuses(existingResource, DISALLOWED_STATUSES);

View file

@ -20,7 +20,6 @@ import static google.registry.util.CollectionUtils.nullToEmpty;
import com.google.common.base.Function;
import com.google.common.collect.Maps;
import google.registry.model.ImmutableObject;
import google.registry.model.contact.ContactResource.Builder;
import google.registry.model.contact.PostalInfo.Type;
import google.registry.model.eppinput.ResourceCommand.AbstractSingleResourceCommand;
import google.registry.model.eppinput.ResourceCommand.ResourceCheck;
@ -75,23 +74,32 @@ public class ContactCommand {
}});
}
@Override
public void applyTo(Builder builder) {
if (authInfo != null) {
builder.setAuthInfo(authInfo);
}
if (disclose != null) {
builder.setDisclose(disclose);
}
if (email != null) {
builder.setEmailAddress(email);
}
if (fax != null) {
builder.setFaxNumber(fax);
}
if (voice != null) {
builder.setVoiceNumber(voice);
}
public ContactPhoneNumber getVoice() {
return voice;
}
public ContactPhoneNumber getFax() {
return fax;
}
public String getEmail() {
return email;
}
public ContactAuthInfo getAuthInfo() {
return authInfo;
}
public Disclose getDisclose() {
return disclose;
}
public PostalInfo getInternationalizedPostalInfo() {
return getPostalInfosAsMap().get(Type.INTERNATIONALIZED);
}
public PostalInfo getLocalizedPostalInfo() {
return getPostalInfosAsMap().get(Type.LOCALIZED);
}
}
@ -134,21 +142,6 @@ public class ContactCommand {
public ContactAuthInfo getAuthInfo() {
return authInfo;
}
@Override
public void applyTo(ContactResource.Builder builder) {
super.applyTo(builder);
if (contactId != null) {
builder.setContactId(contactId);
}
Map<Type, PostalInfo> postalInfosAsMap = getPostalInfosAsMap();
if (postalInfosAsMap.containsKey(Type.INTERNATIONALIZED)) {
builder.setInternationalizedPostalInfo(postalInfosAsMap.get(Type.INTERNATIONALIZED));
}
if (postalInfosAsMap.containsKey(Type.LOCALIZED)) {
builder.setLocalizedPostalInfo(postalInfosAsMap.get(Type.LOCALIZED));
}
}
}
/** A delete command for a {@link ContactResource}. */
@ -204,34 +197,6 @@ public class ContactCommand {
/** The inner change type on a contact update command. */
@XmlType(propOrder = {"postalInfo", "voice", "fax", "email", "authInfo", "disclose"})
public static class Change extends ContactCreateOrChange {
/**
* The spec requires the following behaviors:
* <ul>
* <li>If you update part of a postal info, the fields that you didn't update are unchanged.
* <li>If you update one postal info but not the other, the other is deleted.
* </ul>
* Therefore, if you want to preserve one postal info and update another you need to send the
* update and also something that technically updates the preserved one, even if it only
* "updates" it by setting just one field to the same value.
*/
@Override
public void applyTo(ContactResource.Builder builder) {
super.applyTo(builder);
Map<Type, PostalInfo> postalInfosAsMap = getPostalInfosAsMap();
if (postalInfosAsMap.containsKey(Type.INTERNATIONALIZED)) {
builder.overlayInternationalizedPostalInfo(postalInfosAsMap.get(Type.INTERNATIONALIZED));
if (postalInfosAsMap.size() == 1) {
builder.setLocalizedPostalInfo(null);
}
}
if (postalInfosAsMap.containsKey(Type.LOCALIZED)) {
builder.overlayLocalizedPostalInfo(postalInfosAsMap.get(Type.LOCALIZED));
if (postalInfosAsMap.size() == 1) {
builder.setInternationalizedPostalInfo(null);
}
}
}
}
public static class Change extends ContactCreateOrChange {}
}
}

View file

@ -30,7 +30,6 @@ import google.registry.model.EppResource;
import google.registry.model.EppResource.ForeignKeyedEppResource;
import google.registry.model.annotations.ExternalMessagingName;
import google.registry.model.contact.PostalInfo.Type;
import google.registry.model.eppcommon.AuthInfo;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@ -147,7 +146,7 @@ public class ContactResource extends EppResource implements ForeignKeyedEppResou
return email;
}
public AuthInfo getAuthInfo() {
public ContactAuthInfo getAuthInfo() {
return authInfo;
}

View file

@ -47,7 +47,6 @@ import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DesignatedContact.Type;
import google.registry.model.domain.launch.LaunchNotice;
import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.host.HostResource;
import java.util.Set;
import javax.xml.bind.annotation.XmlElement;
@ -221,7 +220,7 @@ public abstract class DomainBase extends EppResource {
.toSet();
}
public AuthInfo getAuthInfo() {
public DomainAuthInfo getAuthInfo() {
return authInfo;
}

View file

@ -19,7 +19,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.collect.Maps.transformValues;
import static com.google.common.collect.Sets.difference;
import static com.google.common.collect.Sets.intersection;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.util.CollectionUtils.difference;
import static google.registry.util.CollectionUtils.forceEmptyToNull;
@ -37,7 +36,6 @@ import com.googlecode.objectify.Work;
import google.registry.model.EppResource;
import google.registry.model.ImmutableObject;
import google.registry.model.contact.ContactResource;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppinput.ResourceCommand.AbstractSingleResourceCommand;
import google.registry.model.eppinput.ResourceCommand.ResourceCheck;
import google.registry.model.eppinput.ResourceCommand.ResourceCreateOrChange;
@ -98,14 +96,8 @@ public class DomainCommand {
return registrant;
}
@Override
public void applyTo(B builder) {
if (registrant != null) {
builder.setRegistrant(registrant);
}
if (authInfo != null) {
builder.setAuthInfo(authInfo);
}
public DomainAuthInfo getAuthInfo() {
return authInfo;
}
}
@ -175,24 +167,10 @@ public class DomainCommand {
}
@Override
public AuthInfo getAuthInfo() {
public DomainAuthInfo getAuthInfo() {
return authInfo;
}
@Override
public void applyTo(DomainBase.Builder<?, ?> builder) {
super.applyTo(builder);
if (fullyQualifiedDomainName != null) {
builder.setFullyQualifiedDomainName(fullyQualifiedDomainName);
}
if (nameservers != null) {
builder.setNameservers(getNameservers());
}
if (contacts != null) {
builder.setContacts(getContacts());
}
}
/** Creates a copy of this {@link Create} with hard links to hosts and contacts. */
@Override
public Create cloneAndLinkReferences(DateTime now) throws InvalidReferencesException {
@ -422,24 +400,6 @@ public class DomainCommand {
}
}
@Override
public void applyTo(DomainBase.Builder<?, ?> builder) throws AddRemoveSameValueException {
super.applyTo(builder);
getInnerChange().applyTo(builder);
AddRemove add = getInnerAdd();
AddRemove remove = getInnerRemove();
if (!intersection(add.getNameservers(), remove.getNameservers()).isEmpty()) {
throw new AddRemoveSameValueException();
}
builder.addNameservers(add.getNameservers());
builder.removeNameservers(remove.getNameservers());
if (!intersection(add.getContacts(), remove.getContacts()).isEmpty()) {
throw new AddRemoveSameValueException();
}
builder.addContacts(add.getContacts());
builder.removeContacts(remove.getContacts());
}
/**
* Creates a copy of this {@link Update} with hard links to hosts and contacts.
*

View file

@ -14,7 +14,6 @@
package google.registry.model.eppinput;
import static com.google.common.collect.Sets.intersection;
import static google.registry.util.CollectionUtils.nullSafeImmutableCopy;
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
@ -83,9 +82,7 @@ public interface ResourceCommand {
}
/** A create command, or the inner change (as opposed to add or remove) part of an update. */
public interface ResourceCreateOrChange<B extends Builder<?>> {
public abstract void applyTo(B builder);
}
public interface ResourceCreateOrChange<B extends Builder<?>> {}
/**
* An update command for an {@link EppResource}.
@ -133,18 +130,5 @@ public interface ResourceCommand {
A remove = getNullableInnerRemove();
return remove == null ? new TypeInstantiator<A>(getClass()){}.instantiate() : remove;
}
public void applyTo(B builder) throws AddRemoveSameValueException {
getInnerChange().applyTo(builder);
if (!intersection(getInnerAdd().getStatusValues(), getInnerRemove().getStatusValues())
.isEmpty()) {
throw new AddRemoveSameValueException();
}
builder.addStatusValues(getInnerAdd().getStatusValues());
builder.removeStatusValues(getInnerRemove().getStatusValues());
}
}
/** Exception for adding and removing the same value in {@link ResourceUpdate#applyTo}. */
public static class AddRemoveSameValueException extends Exception {}
}

View file

@ -14,7 +14,6 @@
package google.registry.model.host;
import static com.google.common.collect.Sets.intersection;
import static google.registry.util.CollectionUtils.nullSafeImmutableCopy;
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
@ -37,27 +36,9 @@ public class HostCommand {
@XmlTransient
abstract static class HostCreateOrChange extends AbstractSingleResourceCommand
implements ResourceCreateOrChange<HostResource.Builder> {
/** IP Addresses for this host. Can be null if this is an external host. */
@XmlElement(name = "addr")
Set<InetAddress> inetAddresses;
public ImmutableSet<InetAddress> getInetAddresses() {
return nullSafeImmutableCopy(inetAddresses);
}
public String getFullyQualifiedHostName() {
return getTargetId();
}
@Override
public void applyTo(HostResource.Builder builder) {
if (getFullyQualifiedHostName() != null) {
builder.setFullyQualifiedHostName(getFullyQualifiedHostName());
}
if (getInetAddresses() != null) {
builder.setInetAddresses(getInetAddresses());
}
}
}
/**
@ -67,7 +48,15 @@ public class HostCommand {
@XmlType(propOrder = {"targetId", "inetAddresses" })
@XmlRootElement
public static class Create
extends HostCreateOrChange implements ResourceCreateOrChange<HostResource.Builder> {}
extends HostCreateOrChange implements ResourceCreateOrChange<HostResource.Builder> {
/** IP Addresses for this host. Can be null if this is an external host. */
@XmlElement(name = "addr")
Set<InetAddress> inetAddresses;
public ImmutableSet<InetAddress> getInetAddresses() {
return nullSafeImmutableCopy(inetAddresses);
}
}
/** A delete command for a {@link HostResource}. */
@XmlRootElement
@ -124,18 +113,6 @@ public class HostCommand {
}
/** The inner change type on a host update command. */
@XmlType(propOrder = {"targetId", "inetAddresses" })
public static class Change extends HostCreateOrChange {}
@Override
public void applyTo(HostResource.Builder builder) throws AddRemoveSameValueException {
super.applyTo(builder);
if (!intersection(getInnerAdd().getInetAddresses(), getInnerRemove().getInetAddresses())
.isEmpty()) {
throw new AddRemoveSameValueException();
}
builder.addInetAddresses(getInnerAdd().getInetAddresses());
builder.removeInetAddresses(getInnerRemove().getInetAddresses());
}
}
}