Gracefully Loading a Heavy Plugin

Here's the challenge: I have a plug-in which may take more than a few seconds to load. That's not a problem if the plug-in is loaded when the platform starts since the user waits for platform to load anyway. However, if the plug-in is loaded on-demand, after the platform is already started, the user may experience an unexplained freeze. 

To overcome this behavior, it is best to use some progress dialog with a monitor when starting your plugin. This is simple, however, the less-than-trivial question is: how to determine if the platform is starting?  

Those with some knowledge of Eclipse would simply direct me to a very simple API call:

PlatformUI.isWorkbenchRunning()

One major disadvantage.. this is useless, since it will return true when the platform is still loading as well. It is considered running at this point.

Searching in the Eclipse newsgroups portal, I came across another idea:

Bundle b = Platform.getBundle("org.eclipse.swt");
if (b==null || b.getState() != Bundle.ACTIVE) { 
   System.out.println("no UI..."); 
}

This doesn't work, since SWT is already resolved when the splash screen is shown. You can test other bundles, if you'd like, but I find it hard to believe you'll discover any well-defined and consistent difference between the two situations: loading upon launch and loading after it is complete.

My next idea was to check the visibility of the default shell. Nope, it is considered visible at startup. I tried checking for the existence of workbench visual parts and, guess what, they're already there in both cases. After some trial and error I found a very simple way of doing that. One of the distinct features when the splash screen is showing is that you don't see a menu-bar. From that I derived the following test:

Display.getCurrent().getActiveShell().getMenuBar() == null

This will return true when the platform is still launching and a splash screen is shown. Putting it all together and adding all the null checks I could think of, I wrote the following method for checking if the shell is already open and return it if it is:

private Shell findStartedShell() {
   Shell result = null;
   final Display currentDisplay = Display.getCurrent();
   if (currentDisplay != null) {
      result = currentDisplay.getActiveShell();
      if ((result != null) && (result.getMenuBar() == null)) {
         result = null;
      }
   }
   return result;
}


 

I used a ProgressMonitorDialog to show the progress and an IRunnableWithProgress to implement the lengthy startup process. Eventually, the plugin Activator start method would look like this:

public void start(final BundleContext context) throws Exception {
   super.start(context);
   plugin = this;
   final IRunnableWithProgress statupOperation = 
      new IRunnableWithProgress() {

      public void run(final IProgressMonitor monitor) throws
         InvocationTargetException, InterruptedException {
         // do your initialization here
         // use the monitor to set the task name 
         // and report progress

      }
   };

   final Shell activeShell = findStartedShell();
   if (activeShell != null) {
      final ProgressMonitorDialog progressMonitorDialog = 
         new ProgressMonitorDialog(activeShell);
      progressMonitorDialog.run(false, false, statupOperation);
   } else {
      statupOperation.run(new NullProgressMonitor());
   }
} 


The above will do exactly what we were looking for: if the platform is launching, it will proceed with normal startup (the splash screen shows the progress of loading all the plugins) and, if the platform is already loaded, it will show a progress dialog.

Found a better way of doing that?  Let me know in the comments.

From http://zvikico.typepad.com

Article Type: 
How-to
0

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

jeervin92 replied on Wed, 2008/07/23 - 1:32pm

The underlying OSGi container has some notification about when the platform is starting and done coming up.  I believe that it is a FrameworkEvent if my memory serves.  My team and I tried using it a few years ago, but the Eclipse OSGi container would not fully respect it, we never got the done starting event, but we did get to find out when start level 4 was reached, which at the time was the same thing.  I hope that they have fixed this by now.

jeervin92 replied on Wed, 2008/07/23 - 1:47pm

The underlying OSGi container has some notification about when the platform is starting and done coming up.  I believe that it is a FrameworkEvent if my memory serves.  My team and I tried using it a few years ago, but the Eclipse OSGi container would not fully respect it, we never got the done starting event, but we did get to find out when start level 4 was reached, which at the time was the same thing.  I hope that they have fixed this by now.

jeervin92 replied on Wed, 2008/07/23 - 1:55pm

The underlying OSGi container has some notification about when the platform is starting and done coming up.  I believe that it is a FrameworkEvent if my memory serves.  My team and I tried using it a few years ago, but the Eclipse OSGi container would not fully respect it, we never got the done starting event, but we did get to find out when start level 4 was reached, which at the time was the same thing.  I hope that they have fixed this by now.

jeervin92 replied on Wed, 2008/07/23 - 2:26pm

The underlying OSGi container has some notification about when the platform is starting and done coming up.  I believe that it is a FrameworkEvent if my memory serves.  My team and I tried using it a few years ago, but the Eclipse OSGi container would not fully respect it, we never got the done starting event, but we did get to find out when start level 4 was reached, which at the time was the same thing.  I hope that they have fixed this by now.

jeervin92 replied on Wed, 2008/07/23 - 2:27pm

whoops..... anyway to eliminate those duplicates??  I was having connection troubles.  Man it makes me look foolish...

Min Idzelis replied on Thu, 2008/07/24 - 8:53pm

Why not just put your startup code in Job? If you want a progress dialog, why not put that job in a dialog? PlatformUI.getWorkbench().getProgressService().showInDialog(Shell, Job). Careful... the JobManager#isSuspended()==true during workbench restore. Your job won't run until the workbench is actually showing.

Zviki Cohen replied on Fri, 2008/07/25 - 12:01am

@Min,

 You are correct, I tried that technique first. Here's the problem - my plugin becomes active when the user opens a view. The view needs the plugin to be fully loaded. Hence, I cannot allow this to happen in parallel, not knowing who will finish first. 

 I could modify the view to check if everything is loaded and if not show a message until it is. But that's not only one view, it's several views, so It's quite a bit of work.

 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.