Task Launcher - refactored odd use-case

This commit is contained in:
dragonmacher 2019-05-23 14:14:58 -04:00
parent 2cf9f7dded
commit 454ce9c817
7 changed files with 80 additions and 95 deletions

View file

@ -32,8 +32,9 @@ public class MoveBlockTask extends ProgramTask {
private Address currentStart;
private Address newStart;
private MoveBlockListener listener;
private boolean wasCancelled;
private boolean status;
private boolean cancelled;
private String statusMessage;
private boolean success;
/**
* Creates a background command for moving memory blocks. The memory block
@ -62,58 +63,53 @@ public class MoveBlockTask extends ProgramTask {
Memory mem = program.getMemory();
MemoryBlock block = mem.getBlock(currentStart);
monitor.setMessage("Moving Memory Block ...");
String msg = "";
statusMessage = "";
Throwable cause = null;
try {
mem.moveBlock(block, newStart, monitor);
if (monitor.isCancelled()) {
wasCancelled = true;
cancelled = true;
}
else {
status = true;
success = true;
listener.moveBlockCompleted(this);
return;
}
}
catch (OutOfMemoryError e) {
msg = "Insufficient memory to complete operation";
statusMessage = "Insufficient memory to complete operation";
cause = e;
}
catch (NotFoundException exc) {
msg = "Memory block not found";
cause = exc;
catch (NotFoundException e) {
statusMessage = "Memory block not found";
cause = e;
}
catch (MemoryConflictException exc) {
msg = exc.getMessage();
cause = exc;
}
catch (MemoryBlockException exc) {
msg = exc.getMessage();
cause = exc;
}
catch (IllegalArgumentException e) {
msg = e.getMessage();
catch (MemoryConflictException | MemoryBlockException | IllegalArgumentException e) {
statusMessage = e.getMessage();
cause = e;
}
catch (Throwable t) {
Msg.error(this, "Unexpected Exception: " + t.getMessage(), t);
msg = t.getMessage();
if (msg == null) {
msg = t.toString();
statusMessage = t.getMessage();
if (statusMessage == null) {
statusMessage = t.toString();
}
cause = t;
}
monitor.setMessage(msg);
listener.moveBlockCompleted(this);
throw new RollbackException(msg, cause);
throw new RollbackException(statusMessage, cause);
}
public boolean isCancelled() {
return wasCancelled;
return cancelled;
}
public boolean getStatus() {
return status;
public boolean wasSuccessful() {
return success;
}
public String getStatusMessage() {
return statusMessage;
}
}

View file

@ -29,9 +29,9 @@ import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressFactory;
import ghidra.util.HelpLocation;
import ghidra.util.Swing;
import ghidra.util.layout.PairLayout;
import ghidra.util.task.BackgroundThreadTaskLauncher;
import ghidra.util.task.TaskMonitorAdapter;
import ghidra.util.task.TaskBuilder;
/**
* 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 PluginTool tool;
/**
* Constructor for MoveBlockDialog.
*
* @param dialog
* @param title
* @param modal
* @param includeStatus
* @param includeButtons
*/
MoveBlockDialog(MoveBlockModel model, PluginTool tool) {
super("Move Memory Block");
this.model = model;
@ -69,33 +60,22 @@ public class MoveBlockDialog extends DialogComponentProvider implements MoveBloc
addCancelButton();
}
/**
* @see ghidra.app.plugin.contrib.memory.MoveBlockListener#moveBlockCompleted(boolean,
* java.lang.String)
*/
@Override
public void moveBlockCompleted(final MoveBlockTask cmd) {
Runnable r = () -> {
if (cmd.getStatus()) {
close();
model.dispose();
}
else {
public void moveBlockCompleted(MoveBlockTask task) {
setCursor(Cursor.getDefaultCursor());
setOkEnabled(false);
if (cmd.isCancelled()) {
tool.setStatusInfo(getStatusText());
boolean success = task.wasSuccessful();
setOkEnabled(success);
setStatusText(task.getStatusMessage());
Swing.runLater(() -> {
if (success) {
close();
model.dispose();
}
}
};
SwingUtilities.invokeLater(r);
});
}
/**
* @see ghidra.app.plugin.contrib.memory.MoveBlockListener#stateChanged()
*/
@Override
public void stateChanged() {
setOkEnabled(false);
@ -138,18 +118,20 @@ public class MoveBlockDialog extends DialogComponentProvider implements MoveBloc
setOkEnabled(false);
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
BackgroundThreadTaskLauncher launcher = new BackgroundThreadTaskLauncher(model.makeTask());
launcher.run(new TaskMonitorAdapter() {
@Override
public void setMessage(String message) {
setStatusText(message);
}
});
MoveBlockTask task = model.makeTask();
//@formatter:off
TaskBuilder.withTask(task)
.setParent(this.getComponent())
.launchModal()
;
//@formatter:on
}
@Override
protected void cancelCallback() {
close();
model.dispose();
}
private JPanel buildMainPanel() {

View file

@ -17,15 +17,10 @@ package ghidra.app.plugin.core.memory;
import ghidra.app.cmd.memory.MoveBlockListener;
import ghidra.app.cmd.memory.MoveBlockTask;
import ghidra.framework.model.DomainObject;
import ghidra.framework.model.DomainObjectChangedEvent;
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.framework.model.*;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
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
@ -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);
}

View file

@ -30,7 +30,7 @@ import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv;
import ghidra.util.task.*;
import ghidra.util.task.TaskBuilder;
public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
implements MoveBlockListener {
@ -42,7 +42,7 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
private MemoryBlock block;
private volatile boolean moveCompleted;
private volatile boolean status;
private volatile boolean success;
private volatile String errMsg;
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
waitForCondition(() -> moveCompleted && notepad.canLock());
assertTrue("Error message= [" + errMsg + "], ", status);
assertTrue("Error message= [" + errMsg + "], ", success);
}
@Test
@ -145,7 +145,7 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
// wait until the we get the move complete notification
waitForCondition(() -> moveCompleted && notepad.canLock());
assertTrue("Error message= [" + errMsg + "], ", status);
assertTrue("Error message= [" + errMsg + "], ", success);
}
@Test
@ -177,7 +177,7 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
waitForCondition(() -> moveCompleted && x8051.canLock());
setErrorsExpected(false);
assertFalse("Error message= [" + errMsg + "], ", status);
assertFalse("Error message= [" + errMsg + "], ", success);
}
@Test
@ -242,15 +242,10 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
assertNotNull(errMsg);
}
private void launch(Task task) {
private void launch(MoveBlockTask task) {
BackgroundThreadTaskLauncher launcher = new BackgroundThreadTaskLauncher(task);
launcher.run(new TaskMonitorAdapter() {
@Override
public void setMessage(String message) {
errMsg = message;
}
});
TaskBuilder.withTask(task).launchModal();
errMsg = task.getStatusMessage();
}
private Address getNotepadAddr(int offset) {
@ -265,7 +260,7 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
@Override
public void moveBlockCompleted(MoveBlockTask cmd) {
moveCompleted = true;
this.status = cmd.getStatus();
this.success = cmd.wasSuccessful();
}
@Override

View file

@ -221,8 +221,8 @@ public abstract class DataLoadingConstraintEditor<T> extends AbstractColumnConst
reloadDataButton.setVisible(false);
Task task = new LoadDataTask();
task.addTaskListener(this);
BackgroundThreadTaskLauncher launcher = new BackgroundThreadTaskLauncher(task);
launcher.run(taskMonitorComponent);
TaskBuilder.withTask(task).launchInBackground(taskMonitorComponent);
}
@Override

View file

@ -30,15 +30,15 @@ import ghidra.util.TaskUtilities;
*
* <p>See {@link TaskLauncher}.
*/
public class BackgroundThreadTaskLauncher {
class BackgroundThreadTaskLauncher {
private Task task;
public BackgroundThreadTaskLauncher(Task task) {
BackgroundThreadTaskLauncher(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
TaskUtilities.addTrackedTask(task, monitor);
@ -49,5 +49,6 @@ public class BackgroundThreadTaskLauncher {
Thread.currentThread().setName(name);
task.monitoredRun(monitor);
});
}
}

View file

@ -255,6 +255,22 @@ public class TaskBuilder {
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() {
if (title == null) {
throw new NullPointerException("Task title cannot be null");