mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GT-2376: added new task monitor service
This commit is contained in:
parent
538cbc1226
commit
f57af0b730
28 changed files with 1363 additions and 558 deletions
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
package ghidra.util.task;
|
||||
|
||||
import ghidra.util.Issue;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
class StubTaskMonitor implements TaskMonitor {
|
||||
|
@ -83,12 +82,6 @@ class StubTaskMonitor implements TaskMonitor {
|
|||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportIssue(Issue issue) {
|
||||
// stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
// stub
|
||||
|
@ -107,18 +100,6 @@ class StubTaskMonitor implements TaskMonitor {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addIssueListener(IssueListener listener) {
|
||||
// stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeIssueListener(IssueListener listener) {
|
||||
// stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelEnabled(boolean enable) {
|
||||
// stub
|
||||
|
|
|
@ -15,49 +15,93 @@
|
|||
*/
|
||||
package ghidra.util.task;
|
||||
|
||||
import ghidra.util.Issue;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
/**
|
||||
* <CODE>TaskMonitor</CODE> provides an interface by means of which a
|
||||
* potentially long running task can show its progress and also check if the user
|
||||
* has cancelled the operation. Operations that support a task monitor should periodically
|
||||
* has cancelled the operation.
|
||||
* <p>
|
||||
* Operations that support a task monitor should periodically
|
||||
* check to see if the operation has been cancelled and abort. If possible, the
|
||||
* operation should also provide periodic progress information. If it can estimate a
|
||||
* percentage done, then it should use the <code>setProgress(int)</code> method,
|
||||
* otherwise it
|
||||
* should just call the <code>setMessage(String)</code> method.
|
||||
* otherwise it should just call the <code>setMessage(String)</code> method.
|
||||
*/
|
||||
public interface TaskMonitor {
|
||||
|
||||
public static final TaskMonitor DUMMY = new StubTaskMonitor();
|
||||
|
||||
/**
|
||||
* A value to indicate that this monitor has no progress value set.
|
||||
*/
|
||||
/** A value to indicate that this monitor has no progress value set */
|
||||
public static final int NO_PROGRESS_VALUE = -1;
|
||||
|
||||
/**
|
||||
* Returns true if the user has cancelled the operation.
|
||||
* Returns true if the user has cancelled the operation
|
||||
*
|
||||
* @return true if the user has cancelled the operation
|
||||
*/
|
||||
public boolean isCancelled();
|
||||
|
||||
/**
|
||||
* True (the default) signals to paint the progress information inside of the progress bar.
|
||||
* Returns true if the monitor has been initialized
|
||||
*
|
||||
* @return true if the monitor has been initialized
|
||||
*/
|
||||
public default boolean isInitialized() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the initialization state of the monitor
|
||||
*
|
||||
* @param init true for initialized, false otherwise
|
||||
*/
|
||||
public default void setInitialized(boolean init) {
|
||||
// do nothing - this is defaulted for backward compatibility so current
|
||||
// task monitor implementations do not have to change
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the monitor to an uninitialized state. This will result in the primary
|
||||
* monitor being returned from the {@link TaskMonitorService} on the next
|
||||
* invocation.
|
||||
*/
|
||||
public default void reset() {
|
||||
synchronized (this) {
|
||||
setMessage("");
|
||||
setProgress(0);
|
||||
setMaximum(0);
|
||||
setInitialized(false);
|
||||
clearCanceled();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* True (the default) signals to paint the progress information inside of the progress bar
|
||||
*
|
||||
* @param showProgressValue true to paint the progress value; false to not
|
||||
*/
|
||||
public void setShowProgressValue(boolean showProgressValue);
|
||||
|
||||
/**
|
||||
* Sets a message giving additional information about the current
|
||||
* progress.
|
||||
* @param message more information
|
||||
* Sets the message displayed on the task monitor
|
||||
*
|
||||
* @param message the message to display
|
||||
*/
|
||||
public void setMessage(String message);
|
||||
|
||||
/**
|
||||
* Returns a version of this monitor that cannot have its progress state changed. This is
|
||||
* meant for sub-tasks that should not be allowed to hijack task progress.
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public default TaskMonitor getSecondaryMonitor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current progress value.
|
||||
* Sets the current progress value
|
||||
* @param value progress value
|
||||
*/
|
||||
public void setProgress(long value);
|
||||
|
@ -71,7 +115,7 @@ public interface TaskMonitor {
|
|||
public void initialize(long max);
|
||||
|
||||
/**
|
||||
* Set the progress maximum value.
|
||||
* Set the progress maximum value
|
||||
* <p><b>
|
||||
* Note: setting this value will reset the progress to be the max if the progress is currently
|
||||
* greater than the new new max value.
|
||||
|
@ -80,88 +124,70 @@ public interface TaskMonitor {
|
|||
public void setMaximum(long max);
|
||||
|
||||
/**
|
||||
* Returns the current maximum value for progress.
|
||||
* @return
|
||||
* Returns the current maximum value for progress
|
||||
* @return the maximum progress value
|
||||
*/
|
||||
public long getMaximum();
|
||||
|
||||
/**
|
||||
* An indeterminate task monitor may choose to show an animation instead of updating progress.
|
||||
* An indeterminate task monitor may choose to show an animation instead of updating progress
|
||||
* @param indeterminate true if indeterminate
|
||||
*/
|
||||
public void setIndeterminate(boolean indeterminate);
|
||||
|
||||
/**
|
||||
* Check to see if this monitor has been canceled.
|
||||
* @throws CancelledException if monitor has been cancelled.
|
||||
* Check to see if this monitor has been canceled
|
||||
* @throws CancelledException if monitor has been cancelled
|
||||
*/
|
||||
public void checkCanceled() throws CancelledException;
|
||||
|
||||
/**
|
||||
* A convenience method to increment the current progress by the given value.
|
||||
* @param incrementAmount The amount by which to increment the progress.
|
||||
* A convenience method to increment the current progress by the given value
|
||||
* @param incrementAmount The amount by which to increment the progress
|
||||
*/
|
||||
public void incrementProgress(long incrementAmount);
|
||||
|
||||
/**
|
||||
* Returns the current progress value or {@link #NO_PROGRESS_VALUE} if there is no value
|
||||
* set.
|
||||
* set
|
||||
* @return the current progress value or {@link #NO_PROGRESS_VALUE} if there is no value
|
||||
* set.
|
||||
* set
|
||||
*/
|
||||
public long getProgress();
|
||||
|
||||
/**
|
||||
* Notify that an issue occurred while processing.
|
||||
* @param issue the issue that was encountered
|
||||
*/
|
||||
public void reportIssue(Issue issue);
|
||||
|
||||
/**
|
||||
* Cancel the task.
|
||||
* Cancel the task
|
||||
*/
|
||||
public void cancel();
|
||||
|
||||
/**
|
||||
* Add cancelled listener.
|
||||
* @param listener
|
||||
* Add cancelled listener
|
||||
* @param listener the cancel listener
|
||||
*/
|
||||
public void addCancelledListener(CancelledListener listener);
|
||||
|
||||
/**
|
||||
* Remove cancelled listener.
|
||||
* @param listener
|
||||
* Remove cancelled listener
|
||||
* @param listener the cancel listener
|
||||
*/
|
||||
public void removeCancelledListener(CancelledListener listener);
|
||||
|
||||
/**
|
||||
* Set the enablement of the Cancel button.
|
||||
* Set the enablement of the Cancel button
|
||||
* @param enable true means to enable the cancel button
|
||||
*/
|
||||
public void setCancelEnabled(boolean enable);
|
||||
|
||||
/**
|
||||
* Returns true if cancel ability is enabled
|
||||
* @return true if cancel ability is enabled
|
||||
*/
|
||||
public boolean isCancelEnabled();
|
||||
|
||||
/**
|
||||
* Clear the cancellation so that this TaskMonitor may be reused.
|
||||
* Clear the cancellation so that this TaskMonitor may be reused
|
||||
*
|
||||
*/
|
||||
public void clearCanceled();
|
||||
|
||||
/**
|
||||
* Add an issue listener to this monitor.
|
||||
*
|
||||
* @param listener the listener
|
||||
*/
|
||||
public void addIssueListener(IssueListener listener);
|
||||
|
||||
/**
|
||||
* Removes an issue listener to this monitor.
|
||||
*
|
||||
* @param listener the listener
|
||||
*/
|
||||
public void removeIssueListener(IssueListener listener);
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.util.task;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
/**
|
||||
* Provides access to the {@link TaskMonitor} instance for the current thread. The first
|
||||
* time a monitor is requested via {@link #getMonitor()}, a "primary" monitor (one
|
||||
* that allows updating of task progress and status messages) is returned; all
|
||||
* subsequent requests will return a "secondary" monitor, which only allows
|
||||
* status message updates. This is to keep the progress bar from being updated
|
||||
* simultaneously by multiple parties.
|
||||
* <p>
|
||||
* Note: {@link TaskMonitor monitor} instances are registered with this service via the
|
||||
* {@link #register(TaskMonitor) setMonitor} call, and will be available to that thread until
|
||||
* the {@link #remove(int) remove} method is called.
|
||||
* <p>
|
||||
* Note: Because monitor instances are managed by a {@link ThreadLocal} object, they will be
|
||||
* cleaned up automatically by the GC when the thread is terminated.
|
||||
*/
|
||||
public class TaskMonitorService {
|
||||
|
||||
/**
|
||||
* The {@link TaskMonitor} instance. ThreadLocal ensures that each thread has access
|
||||
* to its own monitor.
|
||||
*/
|
||||
private static ThreadLocal<TaskMonitor> localMonitor = new ThreadLocal<TaskMonitor>() {
|
||||
|
||||
/**
|
||||
* Force the initial value to be null so users will have to call
|
||||
* {@link TaskMonitorService#register(TaskMonitor) register} to assign one
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
@Override
|
||||
protected TaskMonitor initialValue() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Unique id for each thread monitor that is assigned when a monitor is
|
||||
* {@link #register(TaskMonitor) registered}. This is to ensure that only clients who have
|
||||
* a valid id can remove a monitor.
|
||||
*/
|
||||
private static ThreadLocal<Integer> localMonitorId = new ThreadLocal<Integer>() {
|
||||
|
||||
@Override
|
||||
protected Integer initialValue() {
|
||||
return nextId.getAndIncrement();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Contains the next unique id for the monitor; this is updated each time a new monitor
|
||||
* is registered with the service.
|
||||
*/
|
||||
private static final AtomicInteger nextId = new AtomicInteger(0);
|
||||
|
||||
/**
|
||||
* Returns the task monitor for the current thread. If one has not yet been registered,
|
||||
* a {@link StubTaskMonitor stub monitor} is returned.
|
||||
*
|
||||
* @return the task monitor
|
||||
*/
|
||||
public synchronized static TaskMonitor getMonitor() {
|
||||
|
||||
if (localMonitor.get() == null) {
|
||||
|
||||
// If no monitor is available, just return a stub. The alternative is to throw an
|
||||
// exception but this isn't considered an error condition in all cases.
|
||||
localMonitor.set(new StubTaskMonitor());
|
||||
}
|
||||
|
||||
// If the monitor has already been initialized, return the secondary monitor to prevent
|
||||
// the caller from hijacking the progress bar
|
||||
if (localMonitor.get().isInitialized()) {
|
||||
return localMonitor.get().getSecondaryMonitor();
|
||||
}
|
||||
|
||||
// This ensures that the next time this method is called, the service
|
||||
// will return the secondary monitor
|
||||
localMonitor.get().setInitialized(true);
|
||||
|
||||
return localMonitor.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given monitor for this thread
|
||||
*
|
||||
* @param monitor the task monitor to register
|
||||
* @return the unique id for the monitor
|
||||
*/
|
||||
public static int register(TaskMonitor monitor) {
|
||||
|
||||
// Don't allow callers to register a monitor if on the swing thread
|
||||
if (SwingUtilities.isEventDispatchThread()) {
|
||||
throw new IllegalArgumentException("Attempting to set a monitor in the Swing thread!");
|
||||
}
|
||||
|
||||
// Don't allow users to register a monitor if there is already one registered for this
|
||||
// thread
|
||||
if (localMonitor.get() != null) {
|
||||
throw new IllegalArgumentException("Task monitor already assigned to this thread");
|
||||
}
|
||||
|
||||
localMonitor.set(monitor);
|
||||
|
||||
return localMonitorId.get();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the monitor from the thread local object. To protect against clients cavalierly
|
||||
* removing monitors, a valid monitor id must be provided; this is generated at the time
|
||||
* of monitor {@link #register(TaskMonitor) registration}.
|
||||
* <p>
|
||||
* Note: This should generally not need to be called as the GC will clean up thread local
|
||||
* objects when the associated thread is finished.
|
||||
*
|
||||
* @param monitorId the unique ID for the monitor to be removed
|
||||
*/
|
||||
public static void remove(int monitorId) {
|
||||
|
||||
if (monitorId != localMonitorId.get()) {
|
||||
throw new IllegalArgumentException("Invalid monitor id for this thread: " + monitorId);
|
||||
}
|
||||
|
||||
localMonitor.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the constructor - this should not be instantiated
|
||||
*/
|
||||
private TaskMonitorService() {
|
||||
// nothing to do
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue