mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
Task Launcher - refactored odd use-case
This commit is contained in:
parent
2cf9f7dded
commit
454ce9c817
7 changed files with 80 additions and 95 deletions
|
@ -32,8 +32,9 @@ public class MoveBlockTask extends ProgramTask {
|
||||||
private Address currentStart;
|
private Address currentStart;
|
||||||
private Address newStart;
|
private Address newStart;
|
||||||
private MoveBlockListener listener;
|
private MoveBlockListener listener;
|
||||||
private boolean wasCancelled;
|
private boolean cancelled;
|
||||||
private boolean status;
|
private String statusMessage;
|
||||||
|
private boolean success;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a background command for moving memory blocks. The memory block
|
* Creates a background command for moving memory blocks. The memory block
|
||||||
|
@ -62,58 +63,53 @@ public class MoveBlockTask extends ProgramTask {
|
||||||
Memory mem = program.getMemory();
|
Memory mem = program.getMemory();
|
||||||
MemoryBlock block = mem.getBlock(currentStart);
|
MemoryBlock block = mem.getBlock(currentStart);
|
||||||
monitor.setMessage("Moving Memory Block ...");
|
monitor.setMessage("Moving Memory Block ...");
|
||||||
String msg = "";
|
statusMessage = "";
|
||||||
Throwable cause = null;
|
Throwable cause = null;
|
||||||
try {
|
try {
|
||||||
mem.moveBlock(block, newStart, monitor);
|
mem.moveBlock(block, newStart, monitor);
|
||||||
if (monitor.isCancelled()) {
|
if (monitor.isCancelled()) {
|
||||||
wasCancelled = true;
|
cancelled = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
status = true;
|
success = true;
|
||||||
listener.moveBlockCompleted(this);
|
listener.moveBlockCompleted(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (OutOfMemoryError e) {
|
catch (OutOfMemoryError e) {
|
||||||
msg = "Insufficient memory to complete operation";
|
statusMessage = "Insufficient memory to complete operation";
|
||||||
cause = e;
|
cause = e;
|
||||||
}
|
}
|
||||||
catch (NotFoundException exc) {
|
catch (NotFoundException e) {
|
||||||
msg = "Memory block not found";
|
statusMessage = "Memory block not found";
|
||||||
cause = exc;
|
cause = e;
|
||||||
}
|
}
|
||||||
catch (MemoryConflictException exc) {
|
catch (MemoryConflictException | MemoryBlockException | IllegalArgumentException e) {
|
||||||
msg = exc.getMessage();
|
statusMessage = e.getMessage();
|
||||||
cause = exc;
|
|
||||||
}
|
|
||||||
catch (MemoryBlockException exc) {
|
|
||||||
msg = exc.getMessage();
|
|
||||||
cause = exc;
|
|
||||||
}
|
|
||||||
catch (IllegalArgumentException e) {
|
|
||||||
msg = e.getMessage();
|
|
||||||
cause = e;
|
cause = e;
|
||||||
}
|
}
|
||||||
catch (Throwable t) {
|
catch (Throwable t) {
|
||||||
Msg.error(this, "Unexpected Exception: " + t.getMessage(), t);
|
Msg.error(this, "Unexpected Exception: " + t.getMessage(), t);
|
||||||
msg = t.getMessage();
|
statusMessage = t.getMessage();
|
||||||
if (msg == null) {
|
if (statusMessage == null) {
|
||||||
msg = t.toString();
|
statusMessage = t.toString();
|
||||||
}
|
}
|
||||||
cause = t;
|
cause = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
monitor.setMessage(msg);
|
|
||||||
listener.moveBlockCompleted(this);
|
listener.moveBlockCompleted(this);
|
||||||
throw new RollbackException(msg, cause);
|
throw new RollbackException(statusMessage, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCancelled() {
|
public boolean isCancelled() {
|
||||||
return wasCancelled;
|
return cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getStatus() {
|
public boolean wasSuccessful() {
|
||||||
return status;
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatusMessage() {
|
||||||
|
return statusMessage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,9 +29,9 @@ import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressFactory;
|
import ghidra.program.model.address.AddressFactory;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
|
import ghidra.util.Swing;
|
||||||
import ghidra.util.layout.PairLayout;
|
import ghidra.util.layout.PairLayout;
|
||||||
import ghidra.util.task.BackgroundThreadTaskLauncher;
|
import ghidra.util.task.TaskBuilder;
|
||||||
import ghidra.util.task.TaskMonitorAdapter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dialog that uses a model to validate the fields for moving a block of memory.
|
* Dialog that uses a model to validate the fields for moving a block of memory.
|
||||||
|
@ -49,15 +49,6 @@ public class MoveBlockDialog extends DialogComponentProvider implements MoveBloc
|
||||||
private MoveBlockModel model;
|
private MoveBlockModel model;
|
||||||
private PluginTool tool;
|
private PluginTool tool;
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for MoveBlockDialog.
|
|
||||||
*
|
|
||||||
* @param dialog
|
|
||||||
* @param title
|
|
||||||
* @param modal
|
|
||||||
* @param includeStatus
|
|
||||||
* @param includeButtons
|
|
||||||
*/
|
|
||||||
MoveBlockDialog(MoveBlockModel model, PluginTool tool) {
|
MoveBlockDialog(MoveBlockModel model, PluginTool tool) {
|
||||||
super("Move Memory Block");
|
super("Move Memory Block");
|
||||||
this.model = model;
|
this.model = model;
|
||||||
|
@ -69,33 +60,22 @@ public class MoveBlockDialog extends DialogComponentProvider implements MoveBloc
|
||||||
addCancelButton();
|
addCancelButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.app.plugin.contrib.memory.MoveBlockListener#moveBlockCompleted(boolean,
|
|
||||||
* java.lang.String)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void moveBlockCompleted(final MoveBlockTask cmd) {
|
public void moveBlockCompleted(MoveBlockTask task) {
|
||||||
Runnable r = () -> {
|
|
||||||
if (cmd.getStatus()) {
|
setCursor(Cursor.getDefaultCursor());
|
||||||
|
boolean success = task.wasSuccessful();
|
||||||
|
setOkEnabled(success);
|
||||||
|
setStatusText(task.getStatusMessage());
|
||||||
|
|
||||||
|
Swing.runLater(() -> {
|
||||||
|
if (success) {
|
||||||
close();
|
close();
|
||||||
model.dispose();
|
model.dispose();
|
||||||
}
|
}
|
||||||
else {
|
});
|
||||||
setCursor(Cursor.getDefaultCursor());
|
|
||||||
setOkEnabled(false);
|
|
||||||
if (cmd.isCancelled()) {
|
|
||||||
tool.setStatusInfo(getStatusText());
|
|
||||||
close();
|
|
||||||
model.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
SwingUtilities.invokeLater(r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.app.plugin.contrib.memory.MoveBlockListener#stateChanged()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void stateChanged() {
|
public void stateChanged() {
|
||||||
setOkEnabled(false);
|
setOkEnabled(false);
|
||||||
|
@ -138,18 +118,20 @@ public class MoveBlockDialog extends DialogComponentProvider implements MoveBloc
|
||||||
setOkEnabled(false);
|
setOkEnabled(false);
|
||||||
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||||
|
|
||||||
BackgroundThreadTaskLauncher launcher = new BackgroundThreadTaskLauncher(model.makeTask());
|
MoveBlockTask task = model.makeTask();
|
||||||
launcher.run(new TaskMonitorAdapter() {
|
|
||||||
@Override
|
//@formatter:off
|
||||||
public void setMessage(String message) {
|
TaskBuilder.withTask(task)
|
||||||
setStatusText(message);
|
.setParent(this.getComponent())
|
||||||
}
|
.launchModal()
|
||||||
});
|
;
|
||||||
|
//@formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void cancelCallback() {
|
protected void cancelCallback() {
|
||||||
close();
|
close();
|
||||||
|
model.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private JPanel buildMainPanel() {
|
private JPanel buildMainPanel() {
|
||||||
|
|
|
@ -17,15 +17,10 @@ package ghidra.app.plugin.core.memory;
|
||||||
|
|
||||||
import ghidra.app.cmd.memory.MoveBlockListener;
|
import ghidra.app.cmd.memory.MoveBlockListener;
|
||||||
import ghidra.app.cmd.memory.MoveBlockTask;
|
import ghidra.app.cmd.memory.MoveBlockTask;
|
||||||
import ghidra.framework.model.DomainObject;
|
import ghidra.framework.model.*;
|
||||||
import ghidra.framework.model.DomainObjectChangedEvent;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.framework.model.DomainObjectListener;
|
|
||||||
import ghidra.program.model.address.Address;
|
|
||||||
import ghidra.program.model.address.AddressFactory;
|
|
||||||
import ghidra.program.model.address.AddressOverflowException;
|
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.mem.MemoryBlock;
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
import ghidra.util.task.Task;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model for moving a memory block; this class does validation of the new start
|
* Model for moving a memory block; this class does validation of the new start
|
||||||
|
@ -172,11 +167,11 @@ class MoveBlockModel implements DomainObjectListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the task that will move the block.
|
* Create the task that will move the block
|
||||||
*
|
*
|
||||||
* @param delay number of ms to delay until the progress dialog is displayed
|
* @return the new task
|
||||||
*/
|
*/
|
||||||
Task makeTask() {
|
MoveBlockTask makeTask() {
|
||||||
return new MoveBlockTask(program, block.getStart(), newStartAddr, listener);
|
return new MoveBlockTask(program, block.getStart(), newStartAddr, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.mem.MemoryBlock;
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||||
import ghidra.test.TestEnv;
|
import ghidra.test.TestEnv;
|
||||||
import ghidra.util.task.*;
|
import ghidra.util.task.TaskBuilder;
|
||||||
|
|
||||||
public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
implements MoveBlockListener {
|
implements MoveBlockListener {
|
||||||
|
@ -42,7 +42,7 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
private MemoryBlock block;
|
private MemoryBlock block;
|
||||||
|
|
||||||
private volatile boolean moveCompleted;
|
private volatile boolean moveCompleted;
|
||||||
private volatile boolean status;
|
private volatile boolean success;
|
||||||
private volatile String errMsg;
|
private volatile String errMsg;
|
||||||
|
|
||||||
private Program buildProgram1(String programName) throws Exception {
|
private Program buildProgram1(String programName) throws Exception {
|
||||||
|
@ -134,7 +134,7 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
|
|
||||||
// wait until the we get the move complete notification
|
// wait until the we get the move complete notification
|
||||||
waitForCondition(() -> moveCompleted && notepad.canLock());
|
waitForCondition(() -> moveCompleted && notepad.canLock());
|
||||||
assertTrue("Error message= [" + errMsg + "], ", status);
|
assertTrue("Error message= [" + errMsg + "], ", success);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -145,7 +145,7 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
|
|
||||||
// wait until the we get the move complete notification
|
// wait until the we get the move complete notification
|
||||||
waitForCondition(() -> moveCompleted && notepad.canLock());
|
waitForCondition(() -> moveCompleted && notepad.canLock());
|
||||||
assertTrue("Error message= [" + errMsg + "], ", status);
|
assertTrue("Error message= [" + errMsg + "], ", success);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -177,7 +177,7 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
waitForCondition(() -> moveCompleted && x8051.canLock());
|
waitForCondition(() -> moveCompleted && x8051.canLock());
|
||||||
setErrorsExpected(false);
|
setErrorsExpected(false);
|
||||||
|
|
||||||
assertFalse("Error message= [" + errMsg + "], ", status);
|
assertFalse("Error message= [" + errMsg + "], ", success);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -242,15 +242,10 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
assertNotNull(errMsg);
|
assertNotNull(errMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void launch(Task task) {
|
private void launch(MoveBlockTask task) {
|
||||||
|
|
||||||
BackgroundThreadTaskLauncher launcher = new BackgroundThreadTaskLauncher(task);
|
TaskBuilder.withTask(task).launchModal();
|
||||||
launcher.run(new TaskMonitorAdapter() {
|
errMsg = task.getStatusMessage();
|
||||||
@Override
|
|
||||||
public void setMessage(String message) {
|
|
||||||
errMsg = message;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Address getNotepadAddr(int offset) {
|
private Address getNotepadAddr(int offset) {
|
||||||
|
@ -265,7 +260,7 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
@Override
|
@Override
|
||||||
public void moveBlockCompleted(MoveBlockTask cmd) {
|
public void moveBlockCompleted(MoveBlockTask cmd) {
|
||||||
moveCompleted = true;
|
moveCompleted = true;
|
||||||
this.status = cmd.getStatus();
|
this.success = cmd.wasSuccessful();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -221,8 +221,8 @@ public abstract class DataLoadingConstraintEditor<T> extends AbstractColumnConst
|
||||||
reloadDataButton.setVisible(false);
|
reloadDataButton.setVisible(false);
|
||||||
Task task = new LoadDataTask();
|
Task task = new LoadDataTask();
|
||||||
task.addTaskListener(this);
|
task.addTaskListener(this);
|
||||||
BackgroundThreadTaskLauncher launcher = new BackgroundThreadTaskLauncher(task);
|
|
||||||
launcher.run(taskMonitorComponent);
|
TaskBuilder.withTask(task).launchInBackground(taskMonitorComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -30,15 +30,15 @@ import ghidra.util.TaskUtilities;
|
||||||
*
|
*
|
||||||
* <p>See {@link TaskLauncher}.
|
* <p>See {@link TaskLauncher}.
|
||||||
*/
|
*/
|
||||||
public class BackgroundThreadTaskLauncher {
|
class BackgroundThreadTaskLauncher {
|
||||||
|
|
||||||
private Task task;
|
private Task task;
|
||||||
|
|
||||||
public BackgroundThreadTaskLauncher(Task task) {
|
BackgroundThreadTaskLauncher(Task task) {
|
||||||
this.task = task;
|
this.task = task;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run(TaskMonitor monitor) {
|
void run(TaskMonitor monitor) {
|
||||||
// add the task here, so we can track it before it is actually started by the thread
|
// add the task here, so we can track it before it is actually started by the thread
|
||||||
TaskUtilities.addTrackedTask(task, monitor);
|
TaskUtilities.addTrackedTask(task, monitor);
|
||||||
|
|
||||||
|
@ -49,5 +49,6 @@ public class BackgroundThreadTaskLauncher {
|
||||||
Thread.currentThread().setName(name);
|
Thread.currentThread().setName(name);
|
||||||
task.monitoredRun(monitor);
|
task.monitoredRun(monitor);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -255,6 +255,22 @@ public class TaskBuilder {
|
||||||
new TaskLauncher(t, parent, delay, dialogWidth);
|
new TaskLauncher(t, parent, delay, dialogWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the task in a background thread with the given monitor that cannot be null. This
|
||||||
|
* is a special case for clients that already have a task monitor widget in their UI and
|
||||||
|
* they wish to let it show the progress of the given task while not blocking the Swing
|
||||||
|
* thread.
|
||||||
|
*
|
||||||
|
* @param monitor the task monitor; may not be null
|
||||||
|
*/
|
||||||
|
public void launchInBackground(TaskMonitor monitor) {
|
||||||
|
// validate(); // not needed since we are in the background
|
||||||
|
Objects.requireNonNull(monitor);
|
||||||
|
BackgroundThreadTaskLauncher launcher =
|
||||||
|
new BackgroundThreadTaskLauncher(new TaskBuilderTask(false));
|
||||||
|
launcher.run(monitor);
|
||||||
|
}
|
||||||
|
|
||||||
private void validate() {
|
private void validate() {
|
||||||
if (title == null) {
|
if (title == null) {
|
||||||
throw new NullPointerException("Task title cannot be null");
|
throw new NullPointerException("Task title cannot be null");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue