/******************************************************************************* * Copyright (c) 2007, 2010 Innoopract Informationssysteme GmbH. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Innoopract Informationssysteme GmbH - initial API and implementation * EclipseSource - ongoing development ******************************************************************************/ package org.eclipse.rwt.internal.lifecycle; import java.util.*; import org.eclipse.rwt.SessionSingletonBase; import org.eclipse.rwt.internal.service.ContextProvider; import org.eclipse.rwt.service.*; import org.eclipse.swt.internal.widgets.IDisplayAdapter; import org.eclipse.swt.widgets.Display; public final class UICallBackManager { public static UICallBackManager getInstance() { Object inst = SessionSingletonBase.getInstance( UICallBackManager.class ); return ( UICallBackManager )inst; } // synchronziation-object to control access to the runnables List final Object lock; // contains a reference to the callback request thread that is currently // blocked. private final Set blockedCallBackRequests; // Flag that indicates whether a request is processed. In that case no // notifications are sent to the client. private boolean uiThreadRunning; // Flag that indicates that a notification was sent to the client. If the new // callback thread returns earlier than the UI Thread the callback thread // must be blocked although the runnbles are not empty private boolean waitForUIThread; // Flag that indicates whether the UICallBack mechanism is active. If not // no callback thread must be blocked. private boolean active; private UICallBackManager() { lock = new Object(); blockedCallBackRequests = new HashSet(); uiThreadRunning = false; waitForUIThread = false; active = false; } boolean isCallBackRequestBlocked() { synchronized( lock ) { return !blockedCallBackRequests.isEmpty(); } } public void setActive( final boolean active ) { synchronized( lock ) { this.active = active; } } public void sendUICallBack() { synchronized( lock ) { if( !uiThreadRunning || !active ) { sendImmediately(); } } } public void sendImmediately() { synchronized( lock ) { lock.notifyAll(); } } void notifyUIThreadStart() { synchronized( lock ) { uiThreadRunning = true; waitForUIThread = false; } } void notifyUIThreadEnd() { synchronized( lock ) { uiThreadRunning = false; if( hasRunnables() ) { sendUICallBack(); } } } boolean hasRunnables() { boolean result = false; Display display = RWTLifeCycle.getSessionDisplay(); if( display != null && !display.isDisposed() ) { IDisplayAdapter adapter = ( IDisplayAdapter )display.getAdapter( IDisplayAdapter.class ); result = adapter.getAsyncRunnablesCount() > 0; } return result; } boolean blockCallBackRequest() { boolean result = false; synchronized( lock ) { final Thread currentThread = Thread.currentThread(); SessionStoreListener listener = new SessionStoreListener() { public void beforeDestroy( final SessionStoreEvent event ) { currentThread.interrupt(); } }; try { if( mustBlockCallBackRequest() ) { blockedCallBackRequests.add( currentThread ); ISessionStore session = ContextProvider.getSession(); session.addSessionStoreListener( listener ); lock.wait(); } } catch( InterruptedException ie ) { result = true; Thread.interrupted(); // Reset interrupted state, see bug 300254 } finally { blockedCallBackRequests.remove( currentThread ); if( !result ) { ContextProvider.getSession().removeSessionStoreListener( listener ); } } waitForUIThread = true; } return result; } private boolean mustBlockCallBackRequest() { return active && blockedCallBackRequests.isEmpty() && ( waitForUIThread || uiThreadRunning || !hasRunnables() ); } }