google-nomulus/java/google/registry/tools/UpdateApplicationStatusCommand.java
Justine Tunney 6f4b059cc9 Make javadoc <p> style guide compliant
This led to confusion for an open source contributor about how to format
code. We don't want to be like, "do as I say, not as I do."

https://google.github.io/styleguide/javaguide.html#s7.1.2-javadoc-paragraphs
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=122589700
2016-05-18 13:09:01 -04:00

184 lines
7.6 KiB
Java

// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.tools;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static google.registry.model.EppResourceUtils.loadByUniqueId;
import static google.registry.model.domain.launch.ApplicationStatus.ALLOCATED;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import com.google.common.collect.ImmutableList;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.googlecode.objectify.VoidWork;
import google.registry.model.domain.DomainApplication;
import google.registry.model.domain.launch.ApplicationStatus;
import google.registry.model.domain.launch.LaunchInfoResponseExtension;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppcommon.Trid;
import google.registry.model.poll.PendingActionNotificationResponse.DomainPendingActionNotificationResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.registrar.Registrar;
import google.registry.model.reporting.HistoryEntry;
import org.joda.time.DateTime;
import java.util.List;
/** Command to manually update the status of a domain application. */
@Parameters(separators = " =", commandDescription = "Manually update domain application status.")
final class UpdateApplicationStatusCommand extends MutatingCommand {
@Parameter(
names = "--ids",
description = "Comma-delimited list of application IDs to update the status.",
required = true)
private List<String> ids;
@Parameter(
names = "--msg",
description = "Message shown to registrars in the poll message.",
required = true)
private String message;
@Parameter(
names = "--status",
description = "The new application status.",
required = true)
private ApplicationStatus newStatus;
@Parameter(
names = "--history_client_id",
description = "Client id that made this change. Only recorded in the history entry.")
private String clientId = "CharlestonRoad";
@Override
protected void init() throws Exception {
checkArgumentNotNull(
Registrar.loadByClientId(clientId), "Registrar with client ID %s not found", clientId);
for (final String applicationId : ids) {
ofy().transact(new VoidWork() {
@Override
public void vrun() {
updateApplicationStatus(applicationId);
}
});
}
}
/**
* Stages changes to update the status of an application and also enqueue a poll message for the
* status change, which may contain a PendingActionNotificationResponse if this is a final status.
*
* <p>This method must be called from within a transaction.
*/
private void updateApplicationStatus(String applicationId) {
ofy().assertInTransaction();
DateTime now = ofy().getTransactionTime();
// Load the domain application.
DomainApplication domainApplication =
loadByUniqueId(DomainApplication.class, applicationId, now);
checkArgumentNotNull(domainApplication, "Domain application does not exist");
// It's not an error if the application already has the intended status. We want the method
// to be idempotent.
if (domainApplication.getApplicationStatus() == newStatus) {
System.err.printf("Domain application %s already has status %s\n", applicationId, newStatus);
return;
}
// Ensure domain does not already have a final status which it should not be updated from.
checkState(
!domainApplication.getApplicationStatus().isFinalStatus(),
"Domain application has final status %s",
domainApplication.getApplicationStatus());
// Update its status.
DomainApplication.Builder applicationBuilder = domainApplication.asBuilder()
.setApplicationStatus(newStatus)
.setLastEppUpdateTime(now)
// Use the current sponsor instead of the history client ID because the latter might be an
// internal client ID that we don't want to expose.
.setLastEppUpdateClientId(domainApplication.getCurrentSponsorClientId());
// Create a history entry (with no XML or Trid) to record that we are updating the status on
// this application.
HistoryEntry newHistoryEntry = new HistoryEntry.Builder()
.setType(HistoryEntry.Type.DOMAIN_APPLICATION_STATUS_UPDATE)
.setParent(domainApplication)
.setModificationTime(now)
.setClientId(clientId)
.setBySuperuser(true)
.build();
// Create a poll message informing the registrar that the application status was updated.
PollMessage.OneTime.Builder pollMessageBuilder = new PollMessage.OneTime.Builder()
.setClientId(domainApplication.getCurrentSponsorClientId())
.setEventTime(ofy().getTransactionTime())
.setMsg(message)
.setParent(newHistoryEntry)
.setResponseExtensions(ImmutableList.of(
new LaunchInfoResponseExtension.Builder()
.setApplicationId(domainApplication.getForeignKey())
.setPhase(domainApplication.getPhase())
.setApplicationStatus(newStatus)
.build()));
// If this is a final status (i.e. an end state), then we should remove pending create from the
// application and include a pending action notification in the poll message. Conversely, if
// this is not a final status, we should add pending create (which will already be there unless
// we're resurrecting an application).
if (newStatus.isFinalStatus()) {
applicationBuilder.removeStatusValue(StatusValue.PENDING_CREATE);
pollMessageBuilder.setResponseData(ImmutableList.of(
DomainPendingActionNotificationResponse.create(
domainApplication.getFullyQualifiedDomainName(),
ALLOCATED.equals(newStatus), // Whether the operation succeeded
getCreationTrid(domainApplication),
now)));
} else {
applicationBuilder.addStatusValue(StatusValue.PENDING_CREATE);
}
// Stage changes for all entities that need to be saved to datastore.
stageEntityChange(domainApplication, applicationBuilder.build());
stageEntityChange(null, pollMessageBuilder.build());
stageEntityChange(null, newHistoryEntry);
}
/** Retrieve the transaction id of the operation which created this application. */
static Trid getCreationTrid(DomainApplication domainApplication) {
Trid creationTrid = domainApplication.getCreationTrid();
if (creationTrid == null) {
// If the creation TRID is not present on the application (this can happen for older
// applications written before this field was added), then we must read the earliest history
// entry for the application to retrieve it.
return checkNotNull(checkNotNull(ofy()
.load()
.type(HistoryEntry.class)
.ancestor(domainApplication)
.order("modificationTime")
.first()
.now()).getTrid());
}
return creationTrid;
}
}