Port PutTopic to use the BatchUpdate interface

Change-Id: I776c8e605610b48e0054921b77053255f037f871
This commit is contained in:
Dave Borowitz
2015-02-20 09:05:33 -08:00
parent fcccc5e4a4
commit 4ddb18d0ba
2 changed files with 72 additions and 59 deletions

View File

@@ -220,7 +220,7 @@ class ChangeApiImpl implements ChangeApi {
in.topic = topic;
try {
putTopic.apply(change, in);
} catch (OrmException | IOException e) {
} catch (OrmException | IOException | UpdateException e) {
throw new RestApiException("Cannot set topic", e);
}
}

View File

@@ -19,7 +19,9 @@ import com.google.gerrit.common.ChangeHooks;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.DefaultInput;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.extensions.webui.UiAction;
import com.google.gerrit.reviewdb.client.Change;
@@ -29,25 +31,29 @@ import com.google.gerrit.server.ChangeMessagesUtil;
import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.change.PutTopic.Input;
import com.google.gerrit.server.index.ChangeIndexer;
import com.google.gerrit.server.git.BatchUpdate;
import com.google.gerrit.server.git.BatchUpdate.ChangeOp;
import com.google.gerrit.server.git.UpdateException;
import com.google.gerrit.server.notedb.ChangeUpdate;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gwtorm.server.AtomicUpdate;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.Collections;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicReference;
@Singleton
public class PutTopic implements RestModifyView<ChangeResource, Input>,
UiAction<ChangeResource> {
private final Provider<ReviewDb> dbProvider;
private final ChangeIndexer indexer;
private final ChangeHooks hooks;
private final ChangeUpdate.Factory updateFactory;
private final ChangeMessagesUtil cmUtil;
private final BatchUpdate.Factory batchUpdateFactory;
public static class Input {
@DefaultInput
@@ -55,80 +61,87 @@ public class PutTopic implements RestModifyView<ChangeResource, Input>,
}
@Inject
PutTopic(Provider<ReviewDb> dbProvider, ChangeIndexer indexer,
ChangeHooks hooks, ChangeUpdate.Factory updateFactory,
ChangeMessagesUtil cmUtil) {
PutTopic(Provider<ReviewDb> dbProvider,
ChangeHooks hooks,
ChangeMessagesUtil cmUtil,
BatchUpdate.Factory batchUpdateFactory) {
this.dbProvider = dbProvider;
this.indexer = indexer;
this.hooks = hooks;
this.updateFactory = updateFactory;
this.cmUtil = cmUtil;
this.batchUpdateFactory = batchUpdateFactory;
}
@Override
public Response<String> apply(ChangeResource req, Input input)
throws AuthException, OrmException, IOException {
throws AuthException, UpdateException, RestApiException, OrmException,
IOException {
if (input == null) {
input = new Input();
}
final String inputTopic = input.topic;
ChangeControl control = req.getControl();
Change change = req.getChange();
if (!control.canEditTopicName()) {
throw new AuthException("changing topic not permitted");
}
ReviewDb db = dbProvider.get();
final String newTopicName = Strings.nullToEmpty(input.topic);
String oldTopicName = Strings.nullToEmpty(change.getTopic());
if (!oldTopicName.equals(newTopicName)) {
String summary;
if (oldTopicName.isEmpty()) {
summary = "Topic set to " + newTopicName;
} else if (newTopicName.isEmpty()) {
summary = "Topic " + oldTopicName + " removed";
} else {
summary = String.format(
"Topic changed from %s to %s",
oldTopicName, newTopicName);
}
final Change.Id id = req.getChange().getId();
final IdentifiedUser caller = (IdentifiedUser) control.getCurrentUser();
final AtomicReference<Change> change = new AtomicReference<>();
final AtomicReference<String> oldTopicName = new AtomicReference<>();
final AtomicReference<String> newTopicName = new AtomicReference<>();
IdentifiedUser currentUser = ((IdentifiedUser) control.getCurrentUser());
ChangeMessage cmsg = new ChangeMessage(
new ChangeMessage.Key(change.getId(), ChangeUtil.messageUUID(db)),
currentUser.getAccountId(), TimeUtil.nowTs(),
change.currentPatchSetId());
cmsg.setMessage(summary);
ChangeUpdate update;
final Timestamp now = TimeUtil.nowTs();
try (BatchUpdate u = batchUpdateFactory.create(dbProvider.get(),
req.getChange().getProject(), now)) {
u.addChangeOp(new ChangeOp(req.getControl()) {
@Override
public void call(ReviewDb db, ChangeUpdate update) throws OrmException,
ResourceConflictException {
Change c = db.changes().get(id);
String n = Strings.nullToEmpty(inputTopic);
String o = Strings.nullToEmpty(c.getTopic());
if (o.equals(n)) {
return;
}
String summary;
if (o.isEmpty()) {
summary = "Topic set to " + n;
} else if (n.isEmpty()) {
summary = "Topic " + o + " removed";
} else {
summary = String.format("Topic changed from %s to %s", o, n);
}
c.setTopic(Strings.emptyToNull(n));
ChangeUtil.updated(c);
db.changes().update(Collections.singleton(c));
db.changes().beginTransaction(change.getId());
try {
change = db.changes().atomicUpdate(change.getId(),
new AtomicUpdate<Change>() {
@Override
public Change update(Change change) {
change.setTopic(Strings.emptyToNull(newTopicName));
ChangeUtil.updated(change);
return change;
}
});
ChangeMessage cmsg = new ChangeMessage(
new ChangeMessage.Key(id, ChangeUtil.messageUUID(db)),
caller.getAccountId(), now, c.currentPatchSetId());
cmsg.setMessage(summary);
cmUtil.addChangeMessage(db, update, cmsg);
//TODO(yyonas): atomic update was not propagated
update = updateFactory.create(control);
cmUtil.addChangeMessage(db, update, cmsg);
db.commit();
} finally {
db.rollback();
}
update.commit();
indexer.index(db, change);
hooks.doTopicChangedHook(change, currentUser.getAccount(),
oldTopicName, db);
change.set(c);
oldTopicName.set(o);
newTopicName.set(n);
}
});
u.addPostOp(new Callable<Void>() {
@Override
public Void call() throws OrmException {
Change c = change.get();
if (c != null) {
hooks.doTopicChangedHook(change.get(), caller.getAccount(),
oldTopicName.get(), dbProvider.get());
}
return null;
}
});
u.execute();
}
return Strings.isNullOrEmpty(newTopicName)
? Response.<String>none()
: Response.ok(newTopicName);
String n = newTopicName.get();
return Strings.isNullOrEmpty(n) ? Response.<String> none() : Response.ok(n);
}
@Override