Jobs API to the Rescue

I have been working on some refactorings to the Turmeric Eclipse Plugins, and one of the issues I have run across are long running tasks that block the UI thread.  The other issue which is related is not allowing these tasks to be canceled or run in the background.

An example is the RegistryRefreshAction class used with the RegistryView.  When a refresh was issued it would block the UI thread and provide no way to cancel it or move it to the background.

Depending on connectivity to some remote maven repositories, the task can take a bit to run, so until it completes you can’t do much.  Here is the old code:

public void run() {
		if (typeLibraryViewer != null) {
			final Runnable runnable = new Runnable() {
				public void run() {
					SOAGlobalRegistryAdapter.getInstance().invalidateRegistry();
					try {
						final Object input = SOAGlobalRegistryAdapter.getInstance()
						.getGlobalRegistry();
						typeLibraryViewer.setInput(input);
						if (typeViewer != null) {
							typeViewer.setInput(input);
						}
					} catch (Exception e) {
						SOALogger.getLogger().error(e);
						throw new RuntimeException(e);
					}
				}
			};
			BusyIndicator.showWhile(null, runnable);
			typeLibraryViewer.refresh();
		}
	}

In order to address this, I did a couple of things.

1. Migrated away from the Action framework and over to the Commands/Handlers framework.  While not necessary to address this issue, it will make future refactorings and contributions to the plugins much easier for adopters.

2. Replaced the custom runnable and BusyIndicator calls with implementations of the Job API and a little bit of Display.asyncExec().

Here is the new code:

	private Job createRegistryRefreshJob() {
		Job job = new Job("Registry Refresh Job") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				monitor.beginTask("Refreshing Registry", 100);
				SOAGlobalRegistryAdapter registryAdapter = SOAGlobalRegistryAdapter.getInstance();
				registryAdapter.invalidateRegistry();
				monitor.worked(50);
				try {
					input = registryAdapter.getGlobalRegistry();
					monitor.worked(30);
				} catch (Exception e) {
					SOALogger.getLogger().error(e);
				}
				if (input != null) {
					Display.getDefault().asyncExec(new Runnable() {

						/**
						 * Refresh the tree viewer with the data
						 */
						public void run() {
							typeLibraryViewer.setInput(input);
							typeLibraryViewer.refresh();
						};
					});
				}
				monitor.done();
				return Status.OK_STATUS;
			}
		};
		return job;
	}

Update: I did a bit of refactoring on the code, which can be seen here.
Now when a user presses the refresh icon, they are presented with the following standard dialog.

They can move the Job to the background if they want and continue on with their tasks.

References:

Advertisements
This entry was posted in clean code, eclipse, turmeric. Bookmark the permalink.

3 Responses to Jobs API to the Rescue

  1. Pingback: Dave Carver: Jobs API to the Rescue

  2. Ian Bull says:

    What part of this is the long running operation? I assume it’s either the invalidate or getGlobalRegistry. If so, these should likely take a progress monitor and then you can pass a submonitor here. Also, you may want to check the monitor to see if cancel has been pressed.

    • kingargyle says:

      @Ian it is the getGlobalRegistry. Also, if you take a look at the updated code link, you’ll see that I did add some checks to see if it has been canceled. You are correct that the getGlobalRegistry should have a submonitor passed to it as well, and also should be run as a job. It can be run independently.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s