Merge remote-tracking branch 'origin/GP-1-dragonmacher-domain-object-with-transaction--SQUASHED'

This commit is contained in:
Ryan Kurtz 2023-08-22 13:12:08 -04:00
commit b261137b40
2 changed files with 92 additions and 35 deletions

View File

@ -272,48 +272,36 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
break; break;
} }
if (!name.equals(block.getName())) { if (!name.equals(block.getName())) {
int id = program.startTransaction("Rename Memory Block");
try { program.withTransaction("Rename Memory Block", () -> {
block.setName(name); try {
program.endTransaction(id, true); block.setName(name);
} }
catch (LockException e) { catch (LockException e) {
program.endTransaction(id, false); provider.setStatusText(e.getMessage());
this.provider.setStatusText(e.getMessage()); }
return; });
}
catch (RuntimeException e1) {
program.endTransaction(id, false);
throw e1;
}
} }
break; break;
case READ: { case READ: {
int id = program.startTransaction("Set Read State");
try { program.withTransaction("Set Read State", () -> {
boolean value = ((Boolean) aValue).booleanValue(); boolean value = ((Boolean) aValue).booleanValue();
block.setRead(value); block.setRead(value);
provider.setStatusText(""); provider.setStatusText("");
program.endTransaction(id, true); });
}
catch (RuntimeException e) {
program.endTransaction(id, false);
throw e;
}
break; break;
} }
case WRITE: { case WRITE: {
int id = program.startTransaction("Set Write State");
try { program.withTransaction("Set Write State", () -> {
boolean value = ((Boolean) aValue).booleanValue(); boolean value = ((Boolean) aValue).booleanValue();
block.setWrite(value); block.setWrite(value);
provider.setStatusText(""); provider.setStatusText("");
program.endTransaction(id, true); });
}
catch (RuntimeException e) {
program.endTransaction(id, false);
throw e;
}
break; break;
} }
case EXECUTE: { case EXECUTE: {
@ -514,8 +502,9 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
} }
private String getByteSourceDescription(List<MemoryBlockSourceInfo> sourceInfos) { private String getByteSourceDescription(List<MemoryBlockSourceInfo> sourceInfos) {
List<MemoryBlockSourceInfo> limited = sourceInfos.size() < 5 ? sourceInfos : sourceInfos.subList(0, 4); List<MemoryBlockSourceInfo> limited =
sourceInfos.size() < 5 ? sourceInfos : sourceInfos.subList(0, 4);
//@formatter:off //@formatter:off
String description = limited String description = limited
.stream() .stream()

View File

@ -18,6 +18,8 @@ package ghidra.framework.model;
import db.TerminatedTransactionException; import db.TerminatedTransactionException;
import db.Transaction; import db.Transaction;
import ghidra.framework.store.LockException; import ghidra.framework.store.LockException;
import utility.function.ExceptionalCallback;
import utility.function.ExceptionalSupplier;
/** /**
* <code>UndoableDomainObject</code> extends a domain object to provide transaction * <code>UndoableDomainObject</code> extends a domain object to provide transaction
@ -48,6 +50,72 @@ public interface UndoableDomainObject extends DomainObject, Undoable {
*/ */
public Transaction openTransaction(String description) throws IllegalStateException; public Transaction openTransaction(String description) throws IllegalStateException;
/**
* Performs the given callback inside of a transaction. Use this method in place of the more
* verbose try/catch/finally semantics.
* <p>
* <pre>
* program.withTransaction("My Description", () -> {
* // ... Do something
* });
* </pre>
*
* <p>
* Note: the transaction created by this method will always be committed when the call is
* finished. If you need the ability to abort transactions, then you need to use the other
* methods on this interface.
*
* @param description brief description of transaction
* @param callback the callback that will be called inside of a transaction
* @throws E any exception that may be thrown in the given callback
*/
public default <E extends Exception> void withTransaction(String description,
ExceptionalCallback<E> callback) throws E {
int id = startTransaction(description);
try {
callback.call();
}
finally {
endTransaction(id, true);
}
}
/**
* Calls the given supplier inside of a transaction. Use this method in place of the more
* verbose try/catch/finally semantics.
* <p>
* <pre>
* program.withTransaction("My Description", () -> {
* // ... Do something
* return result;
* });
* </pre>
* <p>
* If you do not need to supply a result, then use
* {@link #withTransaction(String, ExceptionalCallback)} instead.
*
* @param <E> the exception that may be thrown from this method
* @param <T> the type of result returned by the supplier
* @param description brief description of transaction
* @param supplier the supplier that will be called inside of a transaction
* @return the result returned by the supplier
* @throws E any exception that may be thrown in the given callback
*/
public default <E extends Exception, T> T withTransaction(String description,
ExceptionalSupplier<T, E> supplier) throws E {
T t = null;
boolean success = false;
int id = startTransaction(description);
try {
t = supplier.get();
success = true;
}
finally {
endTransaction(id, success);
}
return t;
}
/** /**
* Start a new transaction in order to make changes to this domain object. * Start a new transaction in order to make changes to this domain object.
* All changes must be made in the context of a transaction. * All changes must be made in the context of a transaction.
@ -90,8 +158,8 @@ public interface UndoableDomainObject extends DomainObject, Undoable {
public TransactionInfo getCurrentTransactionInfo(); public TransactionInfo getCurrentTransactionInfo();
/** /**
* Returns true if the last transaction was terminated externally from the action that * Returns true if the last transaction was terminated from the action that started it.
* started it. * @return true if the last transaction was terminated from the action that started it.
*/ */
public boolean hasTerminatedTransaction(); public boolean hasTerminatedTransaction();
@ -108,7 +176,7 @@ public interface UndoableDomainObject extends DomainObject, Undoable {
* using a shared transaction manager. If either or both is already shared, * using a shared transaction manager. If either or both is already shared,
* a transition to a single shared transaction manager will be * a transition to a single shared transaction manager will be
* performed. * performed.
* @param domainObj * @param domainObj the domain object
* @throws LockException if lock or open transaction is active on either * @throws LockException if lock or open transaction is active on either
* this or the specified domain object * this or the specified domain object
*/ */