Bug 462610 - ApplicationPartServiceImpl#findPart violates contract by throwing IllegalStateException
Summary: ApplicationPartServiceImpl#findPart violates contract by throwing IllegalStat...
Status: RESOLVED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 4.6   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: 4.7 M1   Edit
Assignee: Brian de Alwis CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 498505 (view as bug list)
Depends on:
Blocks:
 
Reported: 2015-03-19 16:53 EDT by Brian de Alwis CLA
Modified: 2016-08-10 10:17 EDT (History)
3 users (show)

See Also:


Attachments
Spy is working on dialog (139.96 KB, image/png)
2015-03-22 20:55 EDT, Patrik Suzzi CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Brian de Alwis CLA 2015-03-19 16:53:02 EDT
Invoking the SpyHandler from a dialog (e.g., the Preferences dialog) fails with an IllegalStateException.

Thread [main] (Suspended (exception IllegalStateException))	
	ApplicationPartServiceImpl.getActiveWindowService() line: 43	
	ApplicationPartServiceImpl.findPart(String) line: 92	
	SpyHandler.run(EPartService, String, MApplication, EModelService) line: 68	

EPartService#findPart() is documented to return null if the view cannot be found.  But ApplicationPartServiceImpl#getActiveWindowService() throws an IllegalStateException which isn't caught.  findPart() should catch the IllegalStateException and return null.
Comment 1 Patrik Suzzi CLA 2015-03-22 20:55:51 EDT
Created attachment 251814 [details]
Spy is working on dialog

Unable to reproduce. 

This is how I tried to reproduce the error: 
1. open a dialog. from menu Window > Preferences
2. Open spy with ALT+SHIFT+F1

Observed behavior:
- Spy is working
- no exception is logged
Comment 2 Brian de Alwis CLA 2015-03-23 10:06:30 EDT
I misclassified this bug, Patrik: this error was caused by the E4 Tools Spy and not the PDE spy.  I suspect I may have messed up the model (this was a debugging image), so it may be a spurious error.  Keeping this open as I'll try to reproduce.
Comment 3 Brian de Alwis CLA 2016-07-26 11:49:19 EDT
*** Bug 498505 has been marked as a duplicate of this bug. ***
Comment 4 Brian de Alwis CLA 2016-07-26 15:40:06 EDT
Moving to Platform/UI.  Finally took a few minutes to look at this in more detail.

Steps to repeat:
  0. Install the E4 Spies (e.g., the CSS Spy)
  1. Open the Preferences dialog
  2. Now try opening one of the Spies, like the CSS Spy (Shift-Alt-F5)

Notice an IllegalStateException is logged to the console.


The SpyHandler looks like the following (lightly reformatted to fit)

   @Execute
   public void run(EPartService ps,
         @Optional @Named(SpyProcessor.SPY_COMMAND_PARAM) String viewID,
         MApplication appli,
         EModelService modelService) {
      MWindow spyWindow = getOrCreateSpyWindow(appli, modelService);
      MPartStack partStack = (MPartStack) modelService.find(E4_SPIES_PART_STACK, spyWindow);
      MPart p = ps.findPart(viewID); // XXX
      if (p == null) {
         // Create the part in the spyWindow...
         p = ps.createPart(viewID);
         partStack.getChildren().add(p);
         partStack.setSelectedElement(p);
      … etc …

There's actually a few issues here.

When the Spy is triggered, the dialog's IEclipseContext is used for lookups, which is rooted from the WorkbenchContext and not its parent window.  I can only think this is so handler lookups don't inadvertently pull in the window handlers?  I haven't investigated this further.

As a result, the SpyHandler's EPartService is resolved to the workbench-level ApplicationPartServiceImpl.  The ApplicationPartServiceImpl attempts to delegate to the active window's EPartService.  It does so by looking at the MApplication's context's activeChild, which in this case is the dialog's context, and so it finds itself.  Since no real EPartService can be found, it throws an IllegalStateException.  The ApplicationPartServiceImpl should be a bit smarter and attempt to look at the MApplication's active window.

But the root cause of this problem is that EPartService is only necessary to create an MPart in a new window.  Really creating a part should be possible from an EModelService.  Especially since we're creating a new window and the EPartService is not actually for that window.

Solutions here:

  1. Enhance ApplicationPartServiceImpl#getActiveWindowService() to attempt to retrieve the EPartService from MApplication's #selectedElement.

  2. Add EModelService#createPart and cause PartServiceImpl#createPart() to delegate to it.  That lets EPartService to still define part-creation policies, but also means that pure E4 windows can be pieced together without an EPartService.

#2 is the preferred solution, I think: EPartService is contextualized to a particular window, and fetching what could be another window's EPartService seems a bit problematic.



Thread [main] (Suspended (exception IllegalStateException))	
	ApplicationPartServiceImpl.getActiveWindowService() line: 43	
	ApplicationPartServiceImpl.findPart(String) line: 92	
	SpyHandler.run(EPartService, String, MApplication, EModelService) line: 67	
	NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]	
	NativeMethodAccessorImpl.invoke(Object, Object[]) line: 62	
	DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43	
	Method.invoke(Object, Object...) line: 498	
	MethodRequestor.execute() line: 56	
	InjectorImpl.invokeUsingClass(Object, Class<?>, Class<Annotation>, Object, PrimaryObjectSupplier, PrimaryObjectSupplier, boolean) line: 252	
	InjectorImpl.invoke(Object, Class<Annotation>, Object, PrimaryObjectSupplier, PrimaryObjectSupplier) line: 234	
	ContextInjectionFactory.invoke(Object, Class<Annotation>, IEclipseContext, IEclipseContext, Object) line: 132	
	WorkbenchHandlerServiceHandler(HandlerServiceHandler).execute(ExecutionEvent) line: 152	
	Command.executeWithChecks(ExecutionEvent) line: 493	
	ParameterizedCommand.executeWithChecks(Object, Object) line: 486	
	HandlerServiceImpl.executeHandler(ParameterizedCommand, IEclipseContext) line: 210	
	KeyBindingDispatcher.executeCommand(ParameterizedCommand, Event) line: 286
Comment 5 Thomas Schindl CLA 2016-07-26 15:50:07 EDT
It's an absolute MUST to use the part-service connected to the window you are dealing with so IMHO only option #2 is viable
Comment 6 Eclipse Genie CLA 2016-07-27 15:35:54 EDT
New Gerrit change created: https://git.eclipse.org/r/78019
Comment 8 Dani Megert CLA 2016-08-10 10:05:58 EDT
Is this done, or more work needed for M2?
Comment 9 Brian de Alwis CLA 2016-08-10 10:17:11 EDT
Oops, it's done.