Bug 218304 - [api][breaking] Spurious NPE during startup due to getAdapter() returning null
Summary: [api][breaking] Spurious NPE during startup due to getAdapter() returning null
Status: RESOLVED FIXED
Alias: None
Product: Target Management
Classification: Tools
Component: RSE (show other bugs)
Version: 3.0   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.0 M6   Edit
Assignee: Martin Oberhuber CLA
QA Contact: Martin Oberhuber CLA
URL:
Whiteboard:
Keywords: api
: 219166 225169 225184 225337 (view as bug list)
Depends on: 82973 203105
Blocks: 248331 181939 225360 226550 226761 227516 227750 227944 228774 229956 231428
  Show dependency tree
 
Reported: 2008-02-08 09:21 EST by Martin Oberhuber CLA
Modified: 2008-09-23 15:18 EDT (History)
6 users (show)

See Also:


Attachments
Patch fixing the issue (247.88 KB, patch)
2008-04-10 11:30 EDT, Martin Oberhuber CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Oberhuber CLA 2008-02-08 09:21:37 EST
RSE Version 3.0M4 on Windows
Seen following traceback 5 times during Workbench startup. On the next session, the NPE did no longer occur.

java.lang.NullPointerException
	at org.eclipse.rse.internal.ui.view.SystemViewSubSystemAdapter.getImageDescriptor(SystemViewSubSystemAdapter.java:120)
	at org.eclipse.rse.internal.ui.view.SystemViewLabelAndContentProvider.getImage(SystemViewLabelAndContentProvider.java:463)
	at org.eclipse.jface.viewers.DecoratingLabelProvider.getImage(DecoratingLabelProvider.java:85)
	at org.eclipse.jface.viewers.DecoratingLabelProvider.updateLabel(DecoratingLabelProvider.java:356)
	at org.eclipse.jface.viewers.WrappedViewerLabelProvider.update(WrappedViewerLabelProvider.java:183)
	at org.eclipse.jface.viewers.ViewerColumn.refresh(ViewerColumn.java:135)
	at org.eclipse.jface.viewers.AbstractTreeViewer.doUpdateItem(AbstractTreeViewer.java:929)
	at org.eclipse.rse.internal.ui.view.SafeTreeViewer.doUpdateItem(SafeTreeViewer.java:71)
	at org.eclipse.rse.internal.ui.view.SystemView.doUpdateItem(SystemView.java:3097)
	at org.eclipse.jface.viewers.AbstractTreeViewer$UpdateItemSafeRunnable.run(AbstractTreeViewer.java:99)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:37)
	at org.eclipse.core.runtime.Platform.run(Platform.java:857)
	at org.eclipse.ui.internal.JFaceUtil$1.run(JFaceUtil.java:46)
	at org.eclipse.jface.util.SafeRunnable.run(SafeRunnable.java:199)
	at org.eclipse.jface.viewers.AbstractTreeViewer.doUpdateItem(AbstractTreeViewer.java:1009)
	at org.eclipse.rse.internal.ui.view.SafeTreeViewer.doUpdateItem(SafeTreeViewer.java:79)
	at org.eclipse.jface.viewers.StructuredViewer$UpdateItemSafeRunnable.run(StructuredViewer.java:466)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:37)
	at org.eclipse.core.runtime.Platform.run(Platform.java:857)
	at org.eclipse.ui.internal.JFaceUtil$1.run(JFaceUtil.java:46)
	at org.eclipse.jface.util.SafeRunnable.run(SafeRunnable.java:199)
	at org.eclipse.jface.viewers.StructuredViewer.updateItem(StructuredViewer.java:2023)
	at org.eclipse.jface.viewers.AbstractTreeViewer.createTreeItem(AbstractTreeViewer.java:824)
	at org.eclipse.rse.internal.ui.view.SystemView.access$1(SystemView.java:1)
	at org.eclipse.rse.internal.ui.view.SystemView$8.run(SystemView.java:6237)
	at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:67)
	at org.eclipse.rse.internal.ui.view.SystemView.createChildren(SystemView.java:6213)
	at org.eclipse.jface.viewers.AbstractTreeViewer.setExpandedState(AbstractTreeViewer.java:2387)
	at org.eclipse.rse.internal.ui.view.SystemViewPart.restoreInitialState(SystemViewPart.java:524)
	at org.eclipse.rse.internal.ui.view.SystemViewPart.access$0(SystemViewPart.java:504)
	at org.eclipse.rse.internal.ui.view.SystemViewPart$4.run(SystemViewPart.java:485)
	at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
	at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:130)
	at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:3727)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3364)
	at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2381)
	at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2345)
	at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2211)
	at org.eclipse.ui.internal.Workbench$4.run(Workbench.java:473)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:288)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:468)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
	at com.windriver.ide.application.CopyOfIDEApplication.start(CopyOfIDEApplication.java:104)
	at com.windriver.ide.application.UnifiedSWTSwingApplication.access$101(UnifiedSWTSwingApplication.java:42)
	at com.windriver.ide.application.UnifiedSWTSwingApplication.start(UnifiedSWTSwingApplication.java:56)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:193)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:106)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:76)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:362)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:175)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:585)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:561)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:501)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1239)
	at org.eclipse.equinox.launcher.Main.main(Main.java:1215)
Comment 1 Martin Oberhuber CLA 2008-02-08 09:36:01 EST
The reason for this NPE seems to be that in following line, adapter==null is the result:

ISubSystemConfigurationAdapter adapter = (ISubSystemConfigurationAdapter)ssFactory.getAdapter(ISubSystemConfigurationAdapter.class);

Since the exception only happens occasionally, it must be a timing issue. In this case, it looks like the adapter factory has not yet been loaded at the time the call is made.

By resolving bug 180519 we made adapter factories declarative and thus able to load lazily. By resolving bug 203105, we implemented automatic activation of UI plugins in a separate thread being spawned at Core initialization. It looks like if this thread is too slow activating the UI, the observed NPE can happen.

It's well known that the kind of UI activation we currently do is not ideal and needs to be improved for better lazy loading. The problem with this is, that we need to find the right places in the UI on which to call IAdapterManager.loadAdapter() to activate the plugins which host the adapter factories. Ideally, the following should hold:
  1.) Only few places with loadAdapter()
  2.) Still enough places to ensure factories are loaded in all cases
  3.) No places with loadAdapter() in the UI thread, especially not
      when opening menus.

Potentially, such a good solution is related to fixing bug 82973 in the Platform, though a fix will also work without that according to bug 82973 comment 30. Potentially, it's also related to avoiding plugin activations where possible and using information from plugin.xml markup instead. 

In the concrete case, for instance, the code just tries to display an image which should really be available in the SubSystemConfigurationProxy and thus not require activating the (files,shells,processes).ui plugin which holds the SubsystemConfigurationAdapter.

So summing up, fixing plugin activation in RSE with respect to getAdapter() will require thorough code review to either replace getAdpater() my mechisms using Markup only, or put loadAdapter() into the proper places.
Comment 2 Martin Oberhuber CLA 2008-02-15 15:42:01 EST
bug 219166 is likely a dup of this one
Comment 3 Martin Oberhuber CLA 2008-02-28 16:00:45 EST
*** Bug 219166 has been marked as a duplicate of this bug. ***
Comment 4 Martin Oberhuber CLA 2008-04-02 10:38:04 EDT
*** Bug 225169 has been marked as a duplicate of this bug. ***
Comment 5 Martin Oberhuber CLA 2008-04-02 10:44:16 EDT
*** Bug 225184 has been marked as a duplicate of this bug. ***
Comment 6 Martin Oberhuber CLA 2008-04-10 11:30:56 EDT
Created attachment 95543 [details]
Patch fixing the issue

Attached patch fixes the issue by improving adapter loading as follows:

1.) Get rid of the forced deferred adapter loader Thread that was added with
    bug 203105 in core.files and similar Activator.start() methods

2.) Add the same Platform.getAdapterManager().loadAdapter() call into the
    various SubSystem.initializeSubSystem() calls. This leads to forced
    adapter loading when the subsystem is connected. Also, fix known 
    overriders of (un)initializeSubSystem() such that they all call super
    as it was already specified in Javadoc. Update Javadocs.

3.) For Subsystems like Local, which don't support individual connecting,
    add a call to initializSubSystem() into the resolveFilterString() methods
    such that adapters are loaded as soon as actual resources are about to 
    get shown.

4.) In some other places (showing menus, filter property page, wizard pages
    etc) where adapter==null, add a fallback to 
    Platform.getAdapterManager().loadAdapter() for loading adapters on demand.
    Some of these places will need to get reviewed to ensure smooth and fast
    operation in all cases. They are all tagged with
       "Lazy Loading:"
    type comments.


This fix needs thorough testing, it's not unlikely that I missed one or the other adapter==null instance which may lead to a NullPointerException, or may lead to silent non-availability of features, menus, property pages, icons or similar. One helper in investigation is to try and operate RSE with minimal number of plugins loaded: Window > Show View > PDE Runtime > Plug-in Registry is the view to use here, with Filter:Active Plugins Only and name filter "rse".

After this fix, rse.shells.ui / rse.files.ui / rse.processes.ui are no longer loaded by default, until a subsystem is connected or expanded, or the submenu of a subsystem is opened.


Migration Notes for Extenders:
------------------------------
Extenders which depend on their adapters being available BEFORE connect for some reason (e.g. custom images, custom actions, especially custom filter actions or icons) will need to provision themselves to eagerly load their UI plugins which declare the adapters. Also, extenders need to ensure that they properly call super.initializeSubSystem() where needed.

At some places, such eager loading may be possible to get rid of by replacing programmatic contributions with declarative (plugin.xml) contributions, e.g. for menus. One example of such a yet-to-do improvement is the "Launch Shell" action, see bug 226550.
Comment 7 Martin Oberhuber CLA 2008-04-10 11:32:38 EDT
Patch committed:
[218304] Improve deferred adapter loading
Comment 8 Martin Oberhuber CLA 2008-04-10 11:58:20 EDT
*** Bug 225337 has been marked as a duplicate of this bug. ***
Comment 9 Martin Oberhuber CLA 2008-04-10 12:00:03 EDT
*** Bug 225337 has been marked as a duplicate of this bug. ***
Comment 10 Martin Oberhuber CLA 2008-04-10 12:18:31 EDT
Marking this as API since the contract is changed how bundles are loaded, and extenders need to observe that as per the migration notes in comment 6, repeated here:

Migration Notes for Extenders:
------------------------------
Extenders which depend on their adapters being available BEFORE connect for
some reason (e.g. custom images, custom actions, especially custom filter
actions or icons) will need to provision themselves to eagerly load their UI
plugins which declare the adapters. Also, extenders need to ensure that they
properly call super.initializeSubSystem() where needed.

At some places, such eager loading may be possible to get rid of by replacing
programmatic contributions with declarative (plugin.xml) contributions, e.g.
for menus. One example of such a yet-to-do improvement is the "Launch Shell"
action, see bug 226550.