Source:
<code>public static void abandon(final PatchSet.Id patchSetId, final IdentifiedUser user, final String message, final ReviewDb db, final AbandonedSender.Factory abandonedSenderFactory, final ChangeHookRunner hooks) throws NoSuchChangeException, InvalidChangeOperationException, EmailException, OrmException { final Change.Id changeId = patchSetId.getParentKey(); final PatchSet patch = db.patchSets().get(patchSetId); if (patch == null) { throw new NoSuchChangeException(changeId); } final ChangeMessage cmsg = new ChangeMessage(new ChangeMessage.Key(changeId, ChangeUtil .messageUUID(db)), user.getAccountId()); final StringBuilder msgBuf = new StringBuilder("Patch Set " + patchSetId.get() + ": Abandoned"); if (message != null && message.length() > 0) { msgBuf.append("\n\n"); msgBuf.append(message); } cmsg.setMessage(msgBuf.toString()); final Change updatedChange = db.changes().atomicUpdate(changeId, new AtomicUpdate<Change>() { @Override public Change update(Change change) { if (change.getStatus().isOpen() && change.currentPatchSetId().equals(patchSetId)) { change.setStatus(Change.Status.ABANDONED); ChangeUtil.updated(change); return change; } else { return null; } } }); if (updatedChange == null) { throw new InvalidChangeOperationException(changeId, <START> "Change is no longer open"); <END> } db.changeMessages().insert(Collections.singleton(cmsg)); final List<PatchSetApproval> approvals = db.patchSetApprovals().byChange(changeId).toList(); for (PatchSetApproval a : approvals) { a.cache(updatedChange); } db.patchSetApprovals().update(approvals); final AbandonedSender cm = abandonedSenderFactory.create(updatedChange); cm.setFrom(user.getAccountId()); cm.setChangeMessage(cmsg); cm.send(); hooks.doChangeAbandonedHook(updatedChange, user.getAccount(), message); }</code><technical_language>This error is hit if change is open, a patch set is lastest patch set. if error message includes this case (similar error message in restore case): "Change is longer open patchset is latest"</technical_language>

Target:
public static void abandon(final PatchSet.Id patchSetId, final IdentifiedUser user, final String message, final ReviewDb db, final AbandonedSender.Factory abandonedSenderFactory, final ChangeHookRunner hooks) throws NoSuchChangeException, InvalidChangeOperationException, EmailException, OrmException { final Change.Id changeId = patchSetId.getParentKey(); final PatchSet patch = db.patchSets().get(patchSetId); if (patch == null) { throw new NoSuchChangeException(changeId); } final ChangeMessage cmsg = new ChangeMessage(new ChangeMessage.Key(changeId, ChangeUtil .messageUUID(db)), user.getAccountId()); final StringBuilder msgBuf = new StringBuilder("Patch Set " + patchSetId.get() + ": Abandoned"); if (message != null && message.length() > 0) { msgBuf.append("\n\n"); msgBuf.append(message); } cmsg.setMessage(msgBuf.toString()); final Change updatedChange = db.changes().atomicUpdate(changeId, new AtomicUpdate<Change>() { @Override public Change update(Change change) { if (change.getStatus().isOpen() && change.currentPatchSetId().equals(patchSetId)) { change.setStatus(Change.Status.ABANDONED); ChangeUtil.updated(change); return change; } else { return null; } } }); if (updatedChange == null) { throw new InvalidChangeOperationException( "Change is no longer open or patchset is not latest"); } db.changeMessages().insert(Collections.singleton(cmsg)); final List<PatchSetApproval> approvals = db.patchSetApprovals().byChange(changeId).toList(); for (PatchSetApproval a : approvals) { a.cache(updatedChange); } db.patchSetApprovals().update(approvals); final AbandonedSender cm = abandonedSenderFactory.create(updatedChange); cm.setFrom(user.getAccountId()); cm.setChangeMessage(cmsg); cm.send(); hooks.doChangeAbandonedHook(updatedChange, user.getAccount(), message); }