Community
Participate
Working Groups
This bug is related to a cluster of bugs already reported, all to do with IllegalStateException thrown by EclipsePreferences.checkRemoved(); easiest way to see some of the cluster is to search on "checkRemoved" in comments. The canonical one is perhaps Bug 68993. This could be fixed (and in many places has been) in client code, but I am reporting this against Platform because I think there is an underlying Platform problem that is tripping up a number of downstream consumers. I suggest solutions at the end of this bug report. *** REPRO *** One repro scenario follows: 1. Start with a workspace that contains a Java project, and with JDT core settings all set to defaults (workspace and project). 2. View workspace settings, go to the Java / Compiler pane, and change compiler compliance at the workspace level to 5.0 (so that there's a workspace node). 3. Select "configure project specific settings" and select the project. In project settings, uncheck "preserve unused local variables" (so there's a project node). 4. Ok the project-specific dialog; ok the workspace dialog. 5. Now, again view workspace settings. Select "configure project specific settings" and select the project. 6. In project settings, click "Restore Defaults". 7. Ok the project-specific dialog; ok the workspace dialog. Note that the error log now contains two errors, an "unhandled loop exception" and "preference node org.eclipse.jdt.core has been removed". *** EXPLANATION *** Here's why I think it's happening in this particular case. For readability I've abbreviated some type names: EP = org.eclipse.core.internal.preferences.EclipsePreferences PP = org.eclipse.core.internal.resources.ProjectPreferences WCM = org.eclipse.ui.internal.preferences.WorkingCopyManager OCB = org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock OCB is used to create preferences panes for certain JDT settings. (We also use it as a base class for the jdt.apt settings, which is how I found this; see Bug 106111.) An OCB owns a WCM. WCM owns a map of WCP. Nothing is ever removed from this map. OCB is used to create both the workspace and project-specific panes. Because those dialogs are cross-linked, it is possible to nest a project-specific instance of OCB within a workspace-prefs instance of OCB, by first viewing a workspace pref pane and then linking to a project-specific pref pane. When the "Configure project specific settings" link on the workspace-prefs instance is clicked, OCB.hasProjectSpecificOptions() is called. In figuring out which projects have options, it inadvertently brings project-specific nodes into the WCM's map - that is, the WCM belonging to the parent (workspace) OCB. Later, when the nested (project-specific) OCB is ok'ed, if the changes cause there to be no non-default settings under the project-specific node, then PP.save() deletes the whole project-specific preference file. This results in the file's resource listener being called. Ultimately, that results in a call to PP.deleted(IFile), which calls PP.removeNode() to remove the corresponding project-specific prefs node. Even later, when the parent (workspace) OCB is ok'ed, it calls WCM.applyChanges (). This flushes every WCP in its map, which includes the project-specific WCP. When a WCP is flushed, it calls PP.flush() on the "original" node that backs it. This results in a call to checkRemove(), which throws an exception if the node has been removed. But in this case, the node that backs the project-specific WCP has already been removed. So, the exception is thrown. *** SOLUTIONS *** In a nutshell, the problem is that WCM is inadvertently caching project pref nodes, but those project nodes can get deleted by underlying code. One workaround would be that in OCB, we could implement hasProjectSpecificSettings() differently, without using a WorkingCopyManager (since we're never interested in actually changing the settings discovered there, there's no point in wrapping them in WCM). But that would only fix the problem in one place; Bugzilla contains many instances of people tripping over the same core problem, which is that it's bad to cache pref nodes. I would suggest instead one of two fixes. Minimally, WCM and WCP could be changed to install listeners on the nodes they cache, to remove the WCP from WCM's map if the underlying node is changed. This would solve the WCM problem, but it would still not solve other caching problems. More deeply, I wonder whether it is right for EclipsePreferences to be throwing exceptions when removed nodes are flushed. Perhaps it would be better to just silently ignore attempts to flush removed nodes? If even the developers of WCM/WCP (in the platform code) make the mistake of caching preference nodes, it may be unreasonable to expect better of downstream consumers.
DJ, it would be good if you could have a look at this. The quick summary is: The preference page builds a working copy preference (WCP1) on top of the original preference store (PS). The page now opens a property page out of the first page that builds a new, unrelated WCP2. That WCP2 is then commited, makes changes to the PS, in particular removing a node. WCS1 doesn't know of this and still holds on the removed node. Any attempt to change the 'removed' node later result in IAExceptions. This all comes from the scenario 'open a property page out of the preference page'. The first question is, shouldn't we really have two different WCSs, or should we share? Sharing would definitly have a benefit, although the nested page has to be carful to only commit its own changes, and not yet committing the other pages changes (would work in our scenario, but tricky in general). We could also think of stacked WCP, where a WCP2 sits on top of WCP1. There it isn't clear to me if the user would understand that pressiong ok on the nested page would not really save the preferences until ok on the top page has been pressed. All that could be easely done in platform.UI by having a stack/instance of the current WCM Possibility 2 is to keep the current separation, but fix the removedNode problem. A node can only be removed if no working copy node refers to it anymore. I guess as the WCP is currently in platform.ui, it has to become a remove listener on the original. But why not using this opportunity to move the WCP down to runtime :-) Possibility 3 is that we change our code to force an apply before opening the property page out of the preference page. This sounds like a bit nasty for the user, but might be the right thing to do if we don't have sharing as suggested in proposal 1. (the remove bug should still be fixed, however)
This problem is fixed in both 3.1.2 and 3.2. I can't find any core changes in these builds related to this, so it must have been with the property and preference pages themselves? Tod and I guess that the WCM was being queried for the wrong nodes. btw, we can't change the behaviour of EclipsePreference#flush as it is spec'd to throw the exception if the node has been removed. Martin do you feel that there is any more work to be done here or can this be closed? How many WCM instances do you use? Is it just one or multiple?
This seems indeed be fixed. I think there were more removed= true calls before. But i can't track back due to the move. It would feel natural if a property page is opened out of a preference page they use the same WCS. But it's ok to me not not try that now.
Ok, closing. We'll keep and eye open and if something else in this area surfaces we will open another report. Thanks.
>It would feel natural if a property page is opened out of a preference page >they use the same WCS. I would disagree as you may be modifying the same preference on a preference different node (that is exactly what you are doing now).
Yes, that's exacly the problem. Now two instances have different copies, so the one who flushes last, wins. In our case, when pressing 'default' on a project, we show you the settings of the workbench. But these are actually not the (unsaved) setting currenly in the preference dialog, but the ones on disk. The fix for us is to always save the settings before opening a property page out of a preference page. It's a minor bug, but in fact I think the right solution is to share the store.
It seems that this bug is still alive, see bug 127986. I suggest to reopen.
*** Bug 127986 has been marked as a duplicate of this bug. ***
I am seeing this error in I20060315-1200 - same steps as Walter's original steps. I reverted some project specific preferences to default, and then clicked ok in the preference dialog to get this error: java.lang.IllegalStateException: Preference node "org.eclipse.jdt.core" has been removed. at org.eclipse.core.internal.preferences.EclipsePreferences.checkRemoved(EclipsePreferences.java:157) at org.eclipse.core.internal.preferences.EclipsePreferences.flush(EclipsePreferences.java:326) at org.eclipse.core.internal.resources.ProjectPreferences.flush(ProjectPreferences.java:566) at org.eclipse.ui.internal.preferences.WorkingCopyPreferences.flush(WorkingCopyPreferences.java:516) at org.eclipse.ui.preferences.WorkingCopyManager.applyChanges(WorkingCopyManager.java:58) at org.eclipse.ui.internal.dialogs.FilteredPreferenceDialog.okPressed(FilteredPreferenceDialog.java:385) at org.eclipse.jface.preference.PreferenceDialog.buttonPressed(PreferenceDialog.java:225) at org.eclipse.jface.dialogs.Dialog$3.widgetSelected(Dialog.java:652) at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:90) at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:66) at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:925) at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3340) at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:2960) at org.eclipse.jface.window.Window.runEventLoop(Window.java:820) at org.eclipse.jface.window.Window.open(Window.java:796) at org.eclipse.ui.dialogs.PropertyDialogAction.run(PropertyDialogAction.java:156) at org.eclipse.jface.action.Action.runWithEvent(Action.java:499) at org.eclipse.jface.action.ActionContributionItem.handleWidgetSelection(ActionContributionItem.java:539) at org.eclipse.jface.action.ActionContributionItem.access$2(ActionContributionItem.java:488) at org.eclipse.jface.action.ActionContributionItem$5.handleEvent(ActionContributionItem.java:400) at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:66) at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:925) at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3340) at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:2960) at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:1909) at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:1873) at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:418) at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:143) at org.eclipse.ui.internal.ide.IDEApplication.run(IDEApplication.java:107) at org.eclipse.core.internal.runtime.PlatformActivator$1.run(PlatformActivator.java:78) at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:92) at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:68) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:374) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:169) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:85) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:58) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:60) at java.lang.reflect.Method.invoke(Method.java:391) at org.eclipse.core.launcher.Main.invokeFramework(Main.java:338) at org.eclipse.core.launcher.Main.basicRun(Main.java:282) at org.eclipse.core.launcher.Main.run(Main.java:977) at org.eclipse.core.launcher.Main.main(Main.java:952)
Created attachment 36815 [details] patch for ui.workbench Here is a patch for WorkingCopyManager which checks to see if any of the nodes in its cache have been removed from underneath it. Another alternative is to register a listener on the original nodes. We will discuss this....after lunch. :-)
Assigning to Tod to release the patch.
Fixed for build >20060327
Verified in 20060328-0100
Please note very similar bug 137398.