Community
Participate
Working Groups
Build Identifier: IES 3.6, UML 2.2 The implementation of the SubsetSupersetEObjectContainmentWithInverseEList causes eGet() (which defaults to resolve=true) when trying to clear the list of guards. Because of this call, eGet actually re-resolves the resource which may be in the process of closing. This leaves the fragment in a bad state (the resource is unloaded, yet its flag is still set to isLoaded=true). This can cause big problems when there are clients who perform postLoad behaviour on newly loaded resources since EObjects existing in the poorly closed resource will not be resolvable and thus look deleted. The following trace shows what happens when I try to close a fragmented class object that contains a transition with a guard. The trace shows that the fragment is being closed, but as the guards are being cleared, it forces a reload, and we end up in RMPResource.load() again, which should not be happening. Thread [main] (Suspended (breakpoint at line 1285 in RMPResource)) RMPResource.load(Map<?,?>) line: 1285 MSLEditingDomain$MSLResourceSet(ResourceSetImpl).demandLoad(Resource) line: 255 MSLEditingDomain$MSLResourceSet(ResourceSetImpl).demandLoadHelper(Resource) line: 270 MSLEditingDomain$MSLResourceSet(ResourceSetImpl).getResource(URI, boolean) line: 354 MSLEditingDomain$MSLResourceSet.getResource(URI, boolean) line: 2444 MSLEditingDomain$MSLResourceSet(ResourceSetImpl).getEObject(URI, boolean) line: 216 EcoreUtil.resolve(EObject, ResourceSet) line: 202 EcoreUtil.resolve(EObject, EObject) line: 262 TransitionImpl(BasicEObjectImpl).eResolveProxy(InternalEObject) line: 1483 TransitionImpl.getGuard() line: 643 TransitionImpl.eGet(int, boolean, boolean) line: 1192 TransitionImpl(BasicEObjectImpl).eGet(EStructuralFeature, boolean, boolean) line: 1021 TransitionImpl(BasicEObjectImpl).eGet(EStructuralFeature, boolean) line: 1013 TransitionImpl(BasicEObjectImpl).eGet(EStructuralFeature) line: 1008 SubsetSupersetEObjectContainmentWithInverseEList$Resolving<E>(SubsetSupersetEObjectEList<E>).subsetRemove(Object) line: 164 SubsetSupersetEObjectContainmentWithInverseEList$Resolving<E>(SubsetSupersetEObjectEList<E>).didRemove(int, E) line: 255 SubsetSupersetEObjectContainmentWithInverseEList$Resolving<E>(AbstractEList<E>).didClear(int, Object[]) line: 172 SubsetSupersetEObjectContainmentWithInverseEList$Resolving<E>(BasicEList<E>).clear() line: 646 SubsetSupersetEObjectContainmentWithInverseEList$Resolving<E>(NotifyingListImpl<E>).doClear() line: 1155 SubsetSupersetEObjectContainmentWithInverseEList$Resolving<E>(NotifyingListImpl<E>).clear() line: 1082 TransitionImpl.eUnset(int) line: 1317 TransitionImpl(BasicEObjectImpl).eUnset(EStructuralFeature) line: 1164 RMPResourceUtil.unloaded(EObject) line: 130 RMPResourceUtil.unloaded(EObject) line: 123 RMPResourceUtil.unloaded(EObject) line: 123 RMPResourceUtil.unloaded(EObject) line: 123 RMPResourceUtil.unload(Resource) line: 101 UMLResourceUtil.unload(Resource) line: 562 CloseFragmentsCommand(CloseResourcesCommand).unloadResource(Resource) line: 599 CloseFragmentsCommand(CloseResourcesCommand).unloadResources(List<Resource>) line: 594 CloseFragmentsCommand(CloseResourcesCommand).closeResources(IProgressMonitor) line: 274 CloseFragmentActionDelegate$1.run() line: 57 MSLEditingDomain$1(MSLTransactionalEditingDomain).runExclusive(Runnable) line: 343 MSLEditingDomain.runExclusive(Runnable) line: 2746 CloseFragmentActionDelegate.doRun(IProgressMonitor) line: 53 CloseFragmentActionDelegate(AbstractActionDelegate).run(IProgressMonitor) line: 391 AbstractModelActionDelegate.access$0(AbstractModelActionDelegate, IProgressMonitor) line: 1 AbstractModelActionDelegate$1.run() line: 73 MSLEditingDomain$1(MSLTransactionalEditingDomain).runExclusive(Runnable) line: 343 MSLEditingDomain.runExclusive(Runnable) line: 2746 CloseFragmentActionDelegate(AbstractModelActionDelegate).run(IProgressMonitor) line: 70 ActionManager$1.run() line: 225 BusyIndicator.showWhile(Display, Runnable) line: 70 ActionManager.run(IActionWithProgress) line: 223 CloseFragmentActionDelegate(AbstractActionDelegate).run(IAction) line: 233 ObjectPluginAction(PluginAction).runWithEvent(Event) line: 251 PluginActionContributionItem(ActionContributionItem).handleWidgetSelection(Event, boolean) line: 584 ActionContributionItem.access$2(ActionContributionItem, Event, boolean) line: 501 ActionContributionItem$5.handleEvent(Event) line: 411 EventTable.sendEvent(Event) line: 84 MenuItem(Widget).sendEvent(Event) line: 1234 Display.runDeferredEvents() line: 3540 Display.readAndDispatch() line: 3159 Workbench.runEventLoop(Window$IExceptionHandler, Display) line: 2629 Workbench.runUI() line: 2593 Workbench.access$4(Workbench) line: 2427 Workbench$7.run() line: 670 Realm.runWithDefault(Realm, Runnable) line: 332 Workbench.createAndRunWorkbench(Display, WorkbenchAdvisor) line: 663 PlatformUI.createAndRunWorkbench(Display, WorkbenchAdvisor) line: 149 IDEApplication.start(IApplicationContext) line: 115 EclipseAppHandle.run(Object) line: 196 EclipseAppLauncher.runApplication(Object) line: 110 EclipseAppLauncher.start(Object) line: 79 EclipseStarter.run(Object) line: 369 EclipseStarter.run(String[], Runnable) line: 179 NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39 DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 37 Method.invoke(Object, Object...) line: 599 Main.invokeFramework(String[], URL[]) line: 619 Main.basicRun(String[]) line: 574 Main.run(String[]) line: 1407 Main.main(String[]) line: 1383 Reproducible: Always Steps to Reproduce: 1. Create a class, add a state machine, add transition with a guard + code 2. Fragment the class 3. close the fragmented class - The class will not close.
Created attachment 173432 [details] don't call eGet with resolve=true during 'remove' Attaching a patch that resolves the issue.
Please provide a test case that can be use to produce this problem in open source. Things like "fragment the class" and "close the fragmented class" don't make sense from an open source UML2 perspective. The proposed patch would introduce other problems; for example, the inability to remove an element from the list in the event that the list was not previously resolved.
I don't think this is a bug in the UML2 subset-superset list implementation. It's a bug in the RMPResourceUtil class (which is not from Eclipse UML2). Look at this part of the stack trace: SubsetSupersetEObjectContainmentWithInverseEList$Resolving<E>(NotifyingListImpl<E>).clear() line: 1082 TransitionImpl.eUnset(int) line: 1317 TransitionImpl(BasicEObjectImpl).eUnset(EStructuralFeature) line: 1164 RMPResourceUtil.unloaded(EObject) line: 130 ... RMPResourceUtil.unload(Resource) line: 101 UMLResourceUtil.unload(Resource) line: 562 CloseFragmentsCommand(CloseResourcesCommand).unloadResource(Resource) line: The RMPResourceUtil is interfering with the unloading of a resource by unsetting a feature of some object that was unloaded. This is not correct. Objects are changed into proxies by the unloading of an EMF resource, and that's all.
Given Christian's comment (thanks for looking into this!), it's not likely we'll be making a change in UML2.