Skip to content

Commit 79f8bea

Browse files
committed
Added withTransaction() to UndoableDomainObject
1 parent ba5fcdf commit 79f8bea

File tree

2 files changed

+92
-35
lines changed

2 files changed

+92
-35
lines changed

Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapModel.java

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -272,48 +272,36 @@ public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
272272
break;
273273
}
274274
if (!name.equals(block.getName())) {
275-
int id = program.startTransaction("Rename Memory Block");
276-
try {
277-
block.setName(name);
278-
program.endTransaction(id, true);
279-
}
280-
catch (LockException e) {
281-
program.endTransaction(id, false);
282-
this.provider.setStatusText(e.getMessage());
283-
return;
284-
}
285-
catch (RuntimeException e1) {
286-
program.endTransaction(id, false);
287-
throw e1;
288-
}
275+
276+
program.withTransaction("Rename Memory Block", () -> {
277+
try {
278+
block.setName(name);
279+
}
280+
catch (LockException e) {
281+
provider.setStatusText(e.getMessage());
282+
}
283+
});
284+
289285
}
290286
break;
291287
case READ: {
292-
int id = program.startTransaction("Set Read State");
293-
try {
288+
289+
program.withTransaction("Set Read State", () -> {
294290
boolean value = ((Boolean) aValue).booleanValue();
295291
block.setRead(value);
296292
provider.setStatusText("");
297-
program.endTransaction(id, true);
298-
}
299-
catch (RuntimeException e) {
300-
program.endTransaction(id, false);
301-
throw e;
302-
}
293+
});
294+
303295
break;
304296
}
305297
case WRITE: {
306-
int id = program.startTransaction("Set Write State");
307-
try {
298+
299+
program.withTransaction("Set Write State", () -> {
308300
boolean value = ((Boolean) aValue).booleanValue();
309301
block.setWrite(value);
310302
provider.setStatusText("");
311-
program.endTransaction(id, true);
312-
}
313-
catch (RuntimeException e) {
314-
program.endTransaction(id, false);
315-
throw e;
316-
}
303+
});
304+
317305
break;
318306
}
319307
case EXECUTE: {
@@ -514,8 +502,9 @@ public Object getColumnValueForRow(MemoryBlock block, int columnIndex) {
514502
}
515503

516504
private String getByteSourceDescription(List<MemoryBlockSourceInfo> sourceInfos) {
517-
List<MemoryBlockSourceInfo> limited = sourceInfos.size() < 5 ? sourceInfos : sourceInfos.subList(0, 4);
518-
505+
List<MemoryBlockSourceInfo> limited =
506+
sourceInfos.size() < 5 ? sourceInfos : sourceInfos.subList(0, 4);
507+
519508
//@formatter:off
520509
String description = limited
521510
.stream()

Ghidra/Framework/Project/src/main/java/ghidra/framework/model/UndoableDomainObject.java

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import db.TerminatedTransactionException;
1919
import db.Transaction;
2020
import ghidra.framework.store.LockException;
21+
import utility.function.ExceptionalCallback;
22+
import utility.function.ExceptionalSupplier;
2123

2224
/**
2325
* <code>UndoableDomainObject</code> extends a domain object to provide transaction
@@ -48,6 +50,72 @@ public interface UndoableDomainObject extends DomainObject, Undoable {
4850
*/
4951
public Transaction openTransaction(String description) throws IllegalStateException;
5052

53+
/**
54+
* Performs the given callback inside of a transaction. Use this method in place of the more
55+
* verbose try/catch/finally semantics.
56+
* <p>
57+
* <pre>
58+
* program.withTransaction("My Description", () -> {
59+
* // ... Do something
60+
* });
61+
* </pre>
62+
*
63+
* <p>
64+
* Note: the transaction created by this method will always be committed when the call is
65+
* finished. If you need the ability to abort transactions, then you need to use the other
66+
* methods on this interface.
67+
*
68+
* @param description brief description of transaction
69+
* @param callback the callback that will be called inside of a transaction
70+
* @throws E any exception that may be thrown in the given callback
71+
*/
72+
public default <E extends Exception> void withTransaction(String description,
73+
ExceptionalCallback<E> callback) throws E {
74+
int id = startTransaction(description);
75+
try {
76+
callback.call();
77+
}
78+
finally {
79+
endTransaction(id, true);
80+
}
81+
}
82+
83+
/**
84+
* Calls the given supplier inside of a transaction. Use this method in place of the more
85+
* verbose try/catch/finally semantics.
86+
* <p>
87+
* <pre>
88+
* program.withTransaction("My Description", () -> {
89+
* // ... Do something
90+
* return result;
91+
* });
92+
* </pre>
93+
* <p>
94+
* If you do not need to supply a result, then use
95+
* {@link #withTransaction(String, ExceptionalCallback)} instead.
96+
*
97+
* @param <E> the exception that may be thrown from this method
98+
* @param <T> the type of result returned by the supplier
99+
* @param description brief description of transaction
100+
* @param supplier the supplier that will be called inside of a transaction
101+
* @return the result returned by the supplier
102+
* @throws E any exception that may be thrown in the given callback
103+
*/
104+
public default <E extends Exception, T> T withTransaction(String description,
105+
ExceptionalSupplier<T, E> supplier) throws E {
106+
T t = null;
107+
boolean success = false;
108+
int id = startTransaction(description);
109+
try {
110+
t = supplier.get();
111+
success = true;
112+
}
113+
finally {
114+
endTransaction(id, success);
115+
}
116+
return t;
117+
}
118+
51119
/**
52120
* Start a new transaction in order to make changes to this domain object.
53121
* All changes must be made in the context of a transaction.
@@ -90,8 +158,8 @@ public interface UndoableDomainObject extends DomainObject, Undoable {
90158
public TransactionInfo getCurrentTransactionInfo();
91159

92160
/**
93-
* Returns true if the last transaction was terminated externally from the action that
94-
* started it.
161+
* Returns true if the last transaction was terminated from the action that started it.
162+
* @return true if the last transaction was terminated from the action that started it.
95163
*/
96164
public boolean hasTerminatedTransaction();
97165

@@ -108,7 +176,7 @@ public interface UndoableDomainObject extends DomainObject, Undoable {
108176
* using a shared transaction manager. If either or both is already shared,
109177
* a transition to a single shared transaction manager will be
110178
* performed.
111-
* @param domainObj
179+
* @param domainObj the domain object
112180
* @throws LockException if lock or open transaction is active on either
113181
* this or the specified domain object
114182
*/

0 commit comments

Comments
 (0)