Bug 280187 - ModalContext removes UICallback too early
Summary: ModalContext removes UICallback too early
Status: RESOLVED FIXED
Alias: None
Product: RAP
Classification: RT
Component: Workbench (show other bugs)
Version: unspecified   Edit
Hardware: All All
: P1 critical (vote)
Target Milestone: 1.3 M7   Edit
Assignee: Project Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords: needinfo
Depends on:
Blocks:
 
Reported: 2009-06-14 04:47 EDT by Sergey N. Yashin CLA
Modified: 2010-04-20 09:50 EDT (History)
4 users (show)

See Also:


Attachments
Demonstrating this bug (15.68 KB, application/zip)
2009-06-16 13:04 EDT, Sergey N. Yashin CLA
no flags Details
patch (1.36 KB, patch)
2009-09-21 05:45 EDT, Benjamin Muskalla CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Comment 1 Rüdiger Herrmann CLA 2009-06-15 06:38:34 EDT
Some code to reproduce would be good. Please see http://wiki.eclipse.org/RAP_Bug_Reporting_Howto
Comment 2 Sergey N. Yashin CLA 2009-06-15 06:54:35 EDT
(In reply to comment #1)
> Some code to reproduce would be good. Please see
> http://wiki.eclipse.org/RAP_Bug_Reporting_Howto
> 

Rüdiger, there is no code to reproduce, its only opens progressmonitor dialog and sometimes this exception appears when the progress monitor dialog is being closed.
Comment 3 Sergey N. Yashin CLA 2009-06-15 06:59:53 EDT
Rüdiger, can you tell me why this exception blocks all rap current and future sessions ? Can i do something to catch this exception in order not to block the rest of the sessions?
Comment 4 Sergey N. Yashin CLA 2009-06-15 08:15:46 EDT
There is code:

                ProgressMonitorDialog downloadingProgress = new ProgressMonitorDialog(shell);
                final String httpRootPath = HNSession.getCurrent().getHttpRoot();
               
                downloadingProgress.run(true, false, new IRunnableWithProgress() {
                    @Override
                    public void run(IProgressMonitor monitor)
                        throws InvocationTargetException, InterruptedException {
                        monitor.beginTask("Выполняется сохранение", IProgressMonitor.UNKNOWN);
                        monitor.subTask("Подготовка...");
                        DownloadsFactory downloadsFactory = DownloadsPlugin.getDefault().getDownloadsFactory();
                        try {
                            final DownloadsItem downloadsItem = downloadsFactory.addDownload(data, httpRootPath);
                           
                            if(downloadsItem != null) {
                                shell.getDisplay().asyncExec(new Runnable() {
                                    @Override
                                    public void run() {
                                        ExternalBrowser.open(String.valueOf(downloadsItem.getIndex()),
                                                downloadsItem.getBrowserURL(), ExternalBrowser.STATUS);
                                    }
                                });
                            } else {
                                shell.getDisplay().asyncExec(new Runnable() {
                                    @Override
                                    public void run() {
                                        MessageDialog.openError(shell, "Сохранить как", "При сохранении возникла ошибка.");
                                    }
                                });
                            }
                        } catch(MaxLoadException e) {
                            shell.getDisplay().asyncExec(new Runnable() {
                                @Override
                                public void run() {
                                    MessageDialog.openInformation(shell, "Сохранить как", "Сервер перегружен, попробуйте сохранить позднее.");
                                }
                            });
                        }
                       
                        monitor.done();
                    }
                });


And code from that code starts:
       saveButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                DownloadsUI.open(saveButton.getShell(), getDetailsTextual().getBytes());
            }
        });
Comment 5 Sergey N. Yashin CLA 2009-06-15 14:18:16 EDT
It happens when runnable is already end and when dialog is closing, inner, while closing, it use code: 
Window.class:
		// stop listening for font changes
		if (fontChangeListener != null) {
			JFaceResources.getFontRegistry().removeListener(fontChangeListener);
			fontChangeListener = null;
		}

There is a problem! While:

	public static FontRegistry getFontRegistry() {
		// RAP [fappel]: 
		return FontRegistryStore.getInstance().getFontRegistry();
//		if (fontRegistry == null) {
//			fontRegistry = new FontRegistry(
//					"org.eclipse.jface.resource.jfacefonts"); //$NON-NLS-1$
//		}
//		return fontRegistry;
		// RAPEND: [bm] 
	}

And when getInstance() is executing on the disposed servlet context (it incorrect ???) the checkState throws exception:

  private void checkState() {
    if( disposed ) {
      throw new IllegalStateException( "The context has been disposed." );
    }
  }


I think in the getInstance need to run in something like runNonUIThreadWithFakeContext, or stay on SWT sample:
//		if (fontRegistry == null) {
//			fontRegistry = new FontRegistry(
//					"org.eclipse.jface.resource.jfacefonts"); //$NON-NLS-1$
//		}
//		return fontRegistry;
Comment 6 Sergey N. Yashin CLA 2009-06-15 14:21:36 EDT
I add the Thread.sleep(3000) in the start of the runnable and all works fine.
Comment 7 Rüdiger Herrmann CLA 2009-06-15 15:26:05 EDT
Hi Sergey,

if you could provide a standalone code snippet, someone could have a look at it. From the comments above I don't get a clue.

Rüdiger
Comment 8 Sergey N. Yashin CLA 2009-06-16 13:04:18 EDT
Created attachment 139320 [details]
Demonstrating this bug
Comment 9 Sergey N. Yashin CLA 2009-06-16 13:06:59 EDT
I attached the code snipplet.
When the project will run, just press several (or more...) times, on the button "Run ProgressMonitorDialog", and you will see that at last the dialog with progress is hangup and there is no closing.
Comment 10 Ivan Furnadjiev CLA 2009-07-09 05:52:01 EDT
Hi Sergey, I can't reproduce it with your project and latest RAP version from CVS HEAD. Tested with FF3.5 and IE8 on Windows Vista. Please check it against CVS HEAD.
Comment 11 Markus Krüger CLA 2009-07-14 11:45:48 EDT
We have the same problem with our application and I can reproduce the problem also with Sergey N. Yashin's sample project with CVS HEAD.
Just keep doubleclicking the button then, after some time, the dialog does not close anymore and RAP hangs, even reload does not work (after reload you at least get the error message about disposed context in eclipse console).

Tried it with Firefox 3.5 on Windows Server 2003.

This is a pretty urgent to fix bug.
Comment 12 Sergey N. Yashin CLA 2009-07-14 12:48:13 EDT
(In reply to comment #11)
> We have the same problem with our application and I can reproduce the problem
> also with Sergey N. Yashin's sample project with CVS HEAD.
> Just keep doubleclicking the button then, after some time, the dialog does not
> close anymore and RAP hangs, even reload does not work (after reload you at
> least get the error message about disposed context in eclipse console).
> 
> Tried it with Firefox 3.5 on Windows Server 2003.
> 
> This is a pretty urgent to fix bug.
> 

Thanks a lot. :-)
Comment 13 Markus Krüger CLA 2009-07-16 05:45:56 EDT
Sorry for posting again, but this bug kills our application all most of the times.
Could some please fix this. I would have provided a patch, but this bug is too deep for me :-(
Comment 14 Benjamin Muskalla CLA 2009-07-21 06:34:59 EDT
Can reproduce that the application hangs from time to time if you click often enough on the button. If you reload the page you get an IAE.

Daemon Thread [UIThread [y9qoreixlsd3]] (Suspended (exception IllegalStateException))	
	ServiceContext.checkState() line: 154	
	ServiceContext.getRequest() line: 82	
	ContextProvider.getRequest() line: 129	
	ContextProvider.getSession() line: 148	
	RWTLifeCycle.setShutdownAdapter(ISessionShutdownAdapter) line: 350	
	RWTLifeCycle.access$0(ISessionShutdownAdapter) line: 347	
	RWTLifeCycle$UIThreadController.run() line: 133	
	UIThread(Thread).run() line: 636	
Comment 15 Markus Krüger CLA 2009-07-21 08:32:00 EDT
Thank god, you can repoduce it :-)
Hope this gets fixed soon, as our customers already complained about the 	occasional crashes.
Comment 16 Benjamin Muskalla CLA 2009-07-21 17:29:22 EDT
Ok, here are some interesting facts:

There are three cases that can happen depending on the timing of the runnable:
a) Runnable in the ModalContextThread will be executed that fast that the joining block method just goes trough and everything happens within one lifecycle run.
b) Runnable needs more time - Thread is created, running the runnable, block() will wait & sleep until everything is done. sleep get waked from time to time trough the UICallback
c) This is the problematic case: Thread is created, UICallback is activated, runnable runs, runnable ends and deactivates UICallback. Shortly after the response is send to the client the block() method gets notified to wake up and join in but it's too late.
Now we are in the following state: UICallback disabled, Dialog is rendered to the client but as we don't have a UICallback, the clientside is blocked by the modal dialog and our UIThread is sleeping. The dialog is already disposed on the server side but these changes are not yet rendered to the clientside. Will see if I can move the UICallback deactivation to the last possible point.

Quick hint for your customers: Just resize the browser window ;-) This triggers a request which wakes up the UIThread and renders the dispose calls for the dialog.
Comment 17 Markus Krüger CLA 2009-08-05 08:53:38 EDT
I have another use case for this bug, too.

Add an IStartup to the rap demo. Within its method just open any dialog. When the dialog opens, then press the reload button of the browser or re-enter the url.
This causes the application to throw the exception and hang up.
It also work in initially shown views that open a dialog in createViewPart.

So this causes also problems in our app, as we want to show the user an error dialog if an exception occurs, which might be just after workbench start.
Comment 18 Benjamin Muskalla CLA 2009-09-21 05:45:23 EDT
Created attachment 147678 [details]
patch

Suggested patch. Moving the deactivation out of the ModalContextThread to the end of the ModalContext#run. Cannot reproduce the bug in the attached snippet with this patch.
Comment 19 Markus Krüger CLA 2009-09-21 06:21:19 EDT
Just checked out the latest CVS, without applying the patch.
The sample project of Sergey still has the problem, but the IStartup with Dialog Problem reported by myself seems to already has been solved (maybe something else fixed it already).

Now I check the patch with Sergey's project.
Comment 20 Markus Krüger CLA 2009-09-21 06:33:25 EDT
Got even worse. Now, working with latest CVS and applied patch the Dialog hangs on first time clicking the button. Tried it more than once. So RAP still hangs.
Comment 21 Ralf Sternberg CLA 2010-04-20 09:50:30 EDT
Changed condition under which enableUICallBack is rendered.
It now respects the case that there are (A)syncRunnables left to process even though the UICallBack has been deactivated.
See UICallBackServiceHandler#isUICallBackActive
Changes are in CVS HEAD.