[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
[rap-dev] CallBack notification system
|
Hello
Could you please review changes from attached patch? I implemented
notification system based on UICallBack mechanism. In the patch there are
necessary changes in platfrom and a little change in org.eclipse.rap.demo. I
added "Redirect"-action on toolbar. It should redirect you from workbench to
about:blank page.
This mechanism allows to push any javascript in users browser. I use it to
mass redirect users on some server events.
It also can be used to inject some additional logic for standard
UICallBack-events (normal callback execution and execution on interrupted
exception).
Maybe this mechanism is not important for RAP as a platform, but it very
useful for any web-application based on RAP.
If this changes have a chance to become a part of RAP project I can try to
prepare necessary tests.
Regards,
Igor
### Eclipse Workspace Patch 1.0
#P org.eclipse.rap.rwt
Index: src/org/eclipse/rwt/internal/lifecycle/UICallBackManager.java
===================================================================
RCS file: /cvsroot/rt/org.eclipse.rap/runtime.rwt/org.eclipse.rap.rwt/src/org/eclipse/rwt/internal/lifecycle/UICallBackManager.java,v
retrieving revision 1.19
diff -u -r1.19 UICallBackManager.java
--- src/org/eclipse/rwt/internal/lifecycle/UICallBackManager.java 4 Jun 2009 11:48:51 -0000 1.19
+++ src/org/eclipse/rwt/internal/lifecycle/UICallBackManager.java 19 Jun 2009 10:56:03 -0000
@@ -11,17 +11,19 @@
******************************************************************************/
package org.eclipse.rwt.internal.lifecycle;
+import java.io.IOException;
import java.util.*;
import org.eclipse.rwt.SessionSingletonBase;
import org.eclipse.rwt.internal.service.ContextProvider;
+import org.eclipse.rwt.lifecycle.*;
import org.eclipse.rwt.service.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
public final class UICallBackManager
- implements SessionStoreListener
+ implements SessionStoreListener, CallBackService
{
public static UICallBackManager getInstance() {
@@ -29,6 +31,8 @@
return ( UICallBackManager )inst;
}
+ private static WeakHashMap managers = new WeakHashMap();
+
private static Timer sendTimer;
// List of RunnableBase or SyncRunnable objects as added by add(A)sync
@@ -49,6 +53,31 @@
// no callback thread must be blocked.
private boolean active;
+
+ private CallBackListener callBackListener;
+
+ private CallBackEvent event;
+
+ public void setCallBackListener(CallBackListener listener) {
+ callBackListener = listener;
+ }
+
+ public boolean processEvent(CallBackEvent event) throws IOException {
+ synchronized( runnablesLock ) {
+ if( callBackListener != null ) {
+ CallBackEvent e = ( CallBackEvent )event.clone();
+ e.dest = this;
+ callBackListener.handleCallBack( e );
+ return e.doit;
+ }
+ return event.doit;
+ }
+ }
+
+ public void writeJSResponse( String message ) throws IOException {
+ UICallBackServiceHandler.writeResponse( message );
+ }
+
private UICallBackManager() {
runnables = new ArrayList();
runnablesLock = new Object();
@@ -56,6 +85,9 @@
uiThreadRunning = false;
waitForUIThread = false;
active = false;
+ synchronized( managers ) {
+ managers.put( this, new Object() );
+ }
}
boolean isCallBackRequestBlocked() {
@@ -92,6 +124,21 @@
}
}
}
+
+ public void sendEvent(CallBackEvent event) {
+ this.event = event;
+ sendImmediately();
+ }
+
+ public static void sendEventToAll( CallBackEvent event ) {
+ synchronized( managers ) {
+ for( Iterator iterator = managers.keySet().iterator(); iterator.hasNext(); )
+ {
+ UICallBackManager manager = ( UICallBackManager )iterator.next();
+ manager.sendEvent( event );
+ }
+ }
+ }
public void sendImmediately() {
synchronized( runnablesLock ) {
@@ -191,9 +238,11 @@
return runnable != null;
}
- boolean blockCallBackRequest() {
- boolean result = false;
+ private static final long MAX_REQUEST_TIME = 120000;
+
+ CallBackEvent blockCallBackRequest() {
synchronized( runnablesLock ) {
+ event = new CallBackEvent(this, UICallBack.EVENT_CODE_CONTINUE, true);
final Thread currentThread = Thread.currentThread();
SessionStoreListener listener = new SessionStoreListener() {
public void beforeDestroy( final SessionStoreEvent event ) {
@@ -205,13 +254,13 @@
locked.add( currentThread );
ISessionStore session = ContextProvider.getSession();
session.addSessionStoreListener( listener );
- runnablesLock.wait();
+ runnablesLock.wait(MAX_REQUEST_TIME);
}
} catch( final InterruptedException ie ) {
- result = true;
+ event = new CallBackEvent(this, UICallBack.EVENT_CODE_ERROR, false);
} finally {
locked.remove( currentThread );
- if( !result ) {
+ if( event.code == UICallBack.EVENT_CODE_ERROR ) {
// TODO [rh] remove the try/catch block once this bug 278258 is fixed
// (Rework ISessionStore#add/removeSessionStoreListener)
try {
@@ -224,7 +273,7 @@
}
waitForUIThread = true;
}
- return result;
+ return event;
}
private boolean mustBlockCallBackRequest() {
@@ -242,6 +291,9 @@
// TODO [rh] revise this when bug #219465 is closed
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=219465
public void beforeDestroy( final SessionStoreEvent event ) {
+ synchronized( managers ) {
+ managers.remove( this );
+ }
synchronized( runnablesLock ) {
if( runnables != null ) {
RunnableBase[] toBeExecuted = new RunnableBase[ runnables.size() ];
Index: src/org/eclipse/rwt/internal/lifecycle/UICallBackServiceHandler.java
===================================================================
RCS file: /cvsroot/rt/org.eclipse.rap/runtime.rwt/org.eclipse.rap.rwt/src/org/eclipse/rwt/internal/lifecycle/UICallBackServiceHandler.java,v
retrieving revision 1.18
diff -u -r1.18 UICallBackServiceHandler.java
--- src/org/eclipse/rwt/internal/lifecycle/UICallBackServiceHandler.java 4 Jun 2009 11:48:51 -0000 1.18
+++ src/org/eclipse/rwt/internal/lifecycle/UICallBackServiceHandler.java 19 Jun 2009 10:56:03 -0000
@@ -417,12 +417,10 @@
}
public void service() throws IOException, ServletException {
- ISessionStore sessionStore = RWT.getSessionStore();
- if( !UICallBackManager.getInstance().blockCallBackRequest()
- && ContextProvider.hasContext()
- && sessionStore.isBound() )
- {
- writeResponse();
+ UICallBackManager manager = UICallBackManager.getInstance();
+ CallBackEvent event = manager.blockCallBackRequest();
+ if( manager.processEvent( event ) ) {
+ writeResponse( jsUICallBack() );
}
}
@@ -552,15 +550,19 @@
//////////////////////////
// Service helping methods
- static void writeResponse() throws IOException {
- HttpServletResponse response = ContextProvider.getResponse();
- response.setHeader( HTML.CONTENT_TYPE, HTML.CONTENT_TEXT_JAVASCRIPT_UTF_8 );
- PrintWriter writer = response.getWriter();
- writer.print( jsUICallBack() );
- writer.flush();
+ static void writeResponse( String message ) throws IOException {
+ ISessionStore sessionStore = RWT.getSessionStore();
+ if( ContextProvider.hasContext() && sessionStore.isBound() ) {
+ HttpServletResponse response = ContextProvider.getResponse();
+ response.setHeader( HTML.CONTENT_TYPE, HTML.CONTENT_TEXT_JAVASCRIPT_UTF_8 );
+ PrintWriter writer = response.getWriter();
+ writer.print( message );
+ writer.flush();
+ }
}
- private static String jsUICallBack() {
+ // public for tests only
+ public static String jsUICallBack() {
String result;
if( isUICallBackActive()
&& !UICallBackManager.getInstance().isCallBackRequestBlocked() )
Index: src/org/eclipse/rwt/lifecycle/UICallBack.java
===================================================================
RCS file: /cvsroot/rt/org.eclipse.rap/runtime.rwt/org.eclipse.rap.rwt/src/org/eclipse/rwt/lifecycle/UICallBack.java,v
retrieving revision 1.8
diff -u -r1.8 UICallBack.java
--- src/org/eclipse/rwt/lifecycle/UICallBack.java 12 Jun 2008 13:12:18 -0000 1.8
+++ src/org/eclipse/rwt/lifecycle/UICallBack.java 19 Jun 2009 10:56:03 -0000
@@ -11,6 +11,7 @@
package org.eclipse.rwt.lifecycle;
+import org.eclipse.rwt.internal.lifecycle.UICallBackManager;
import org.eclipse.rwt.internal.lifecycle.UICallBackServiceHandler;
import org.eclipse.swt.widgets.Display;
@@ -21,7 +22,10 @@
* @since 1.0
*/
public final class UICallBack {
-
+
+ public static final int EVENT_CODE_ERROR = 0;
+ public static final int EVENT_CODE_CONTINUE = 1;
+
/**
* Sometimes a background thread needs to access values that are stored
* in the session object that started the thread. In particular these
@@ -68,6 +72,18 @@
UICallBackServiceHandler.activateUICallBacksFor( id );
}
+ public static void setCallBackListener(CallBackListener listener) {
+ UICallBackManager.getInstance().setCallBackListener( listener );
+ }
+
+ public static void sendEvent(CallBackEvent event) {
+ UICallBackManager.getInstance().sendEvent( event );
+ }
+
+ public static void sendEventToAll(CallBackEvent event) {
+ UICallBackManager.sendEventToAll( event );
+ }
+
/**
* To allow automatic UI-updates by server side background threads
* activate the UICallBack mechanism. Call {@link UICallBack#deactivate} method
Index: src/org/eclipse/rwt/lifecycle/CallBackEvent.java
===================================================================
RCS file: src/org/eclipse/rwt/lifecycle/CallBackEvent.java
diff -N src/org/eclipse/rwt/lifecycle/CallBackEvent.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/rwt/lifecycle/CallBackEvent.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2009 EclipseSource and others. 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:
+ * EclipseSource - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rwt.lifecycle;
+
+import java.util.EventObject;
+
+import org.eclipse.rwt.internal.lifecycle.UICallBackManager;
+
+public class CallBackEvent extends EventObject implements Cloneable {
+
+ private static final long serialVersionUID = 2648996217148845076L;
+
+ public int code;
+ public boolean doit;
+ public Object data;
+ public CallBackService source;
+ public CallBackService dest;
+
+ public CallBackEvent( CallBackService source, int code, boolean doit ) {
+ super( source );
+ this.source = source;
+ this.code = code;
+ this.doit = doit;
+ }
+
+ public CallBackEvent( int code, boolean doit ) {
+ this( UICallBackManager.getInstance(), code, doit );
+ }
+
+ public CallBackEvent( int code ) {
+ this( UICallBackManager.getInstance(), code, true );
+ }
+
+ public Object clone() {
+ CallBackEvent clone = new CallBackEvent( source, code, doit );
+ clone.data = data;
+ return clone;
+ }
+}
Index: src/org/eclipse/rwt/lifecycle/CallBackService.java
===================================================================
RCS file: src/org/eclipse/rwt/lifecycle/CallBackService.java
diff -N src/org/eclipse/rwt/lifecycle/CallBackService.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/rwt/lifecycle/CallBackService.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ * Copyright (c) 2009 EclipseSource and others. 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:
+ * EclipseSource - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rwt.lifecycle;
+
+import java.io.IOException;
+
+
+public interface CallBackService {
+ public void writeJSResponse(String message) throws IOException;
+}
Index: src/org/eclipse/rwt/lifecycle/CallBackListener.java
===================================================================
RCS file: src/org/eclipse/rwt/lifecycle/CallBackListener.java
diff -N src/org/eclipse/rwt/lifecycle/CallBackListener.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/rwt/lifecycle/CallBackListener.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2009 EclipseSource and others. 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:
+ * EclipseSource - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rwt.lifecycle;
+
+import java.io.IOException;
+import java.util.EventListener;
+
+
+public interface CallBackListener extends EventListener {
+ void handleCallBack(CallBackEvent event) throws IOException;
+}
#P org.eclipse.rap.rwt.q07
Index: js/org/eclipse/swt/Request.js
===================================================================
RCS file: /cvsroot/rt/org.eclipse.rap/runtime.rwt/org.eclipse.rap.rwt.q07/js/org/eclipse/swt/Request.js,v
retrieving revision 1.15
diff -u -r1.15 Request.js
--- js/org/eclipse/swt/Request.js 4 Jun 2009 11:48:55 -0000 1.15
+++ js/org/eclipse/swt/Request.js 19 Jun 2009 10:56:05 -0000
@@ -38,10 +38,13 @@
// References the currently running request or null if no request is active
this._currentRequest = null;
this._timeoutPage = "";
+
+ this._disabled = false;
},
destruct : function() {
this._currentRequest = null;
+ this._disabled = null;
},
events : {
@@ -141,6 +144,15 @@
qx.client.Timer.once( func, this, 60 );
}
},
+
+ disable : function() {
+ this._disabled = true;
+ },
+
+ redirect : function( url ) {
+ this.disable();
+ window.document.location.href = url;
+ },
sendSyncronous : function() {
this._sendImmediate( false );
@@ -250,6 +262,10 @@
// [vt] workaround for bug #253756: Copied code from _handleSending since
// the sending phase is skipped on failure in IE
// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=253756
+ if (this._disabled) {
+ return;
+ }
+
var exchange = evt.getTarget();
this._currentRequest = exchange.getRequest();
var giveUp = true;
@@ -281,6 +297,9 @@
},
_handleCompleted : function( evt ) {
+ if (this._disabled) {
+ return;
+ }
var text = evt.getTarget().getImplementation().getRequest().responseText;
if( text && text.indexOf( "<!DOCTYPE" ) === 0 ) {
// Handle request to timed out session: write info page and offer
#P org.eclipse.rap.rwt.test
Index: src/org/eclipse/rwt/internal/lifecycle/UICallBackServiceHandler_Test.java
===================================================================
RCS file: /cvsroot/rt/org.eclipse.rap/runtime.rwt.test/org.eclipse.rap.rwt.test/src/org/eclipse/rwt/internal/lifecycle/UICallBackServiceHandler_Test.java,v
retrieving revision 1.4
diff -u -r1.4 UICallBackServiceHandler_Test.java
--- src/org/eclipse/rwt/internal/lifecycle/UICallBackServiceHandler_Test.java 4 Jun 2009 11:49:01 -0000 1.4
+++ src/org/eclipse/rwt/internal/lifecycle/UICallBackServiceHandler_Test.java 19 Jun 2009 10:56:06 -0000
@@ -68,7 +68,7 @@
Fixture.fakeResponseWriter();
TestResponse response = ( TestResponse )ContextProvider.getResponse();
response.setOutputStream( new TestServletOutputStream() );
- UICallBackServiceHandler.writeResponse();
+ UICallBackServiceHandler.writeResponse( UICallBackServiceHandler.jsUICallBack() );
assertEquals( HTML.CONTENT_TEXT_JAVASCRIPT_UTF_8,
response.getHeader( "Content-Type" ) );
}
#P org.eclipse.rap.demo
Index: src/org/eclipse/rap/demo/DemoWorkbench.java
===================================================================
RCS file: /cvsroot/rt/org.eclipse.rap/runtime.ui/org.eclipse.rap.demo/src/org/eclipse/rap/demo/DemoWorkbench.java,v
retrieving revision 1.10
diff -u -r1.10 DemoWorkbench.java
--- src/org/eclipse/rap/demo/DemoWorkbench.java 12 Jun 2008 14:00:46 -0000 1.10
+++ src/org/eclipse/rap/demo/DemoWorkbench.java 19 Jun 2009 10:56:07 -0000
@@ -11,8 +11,11 @@
package org.eclipse.rap.demo;
+import java.io.IOException;
+import java.text.MessageFormat;
+
import org.eclipse.rap.demo.presentation.DemoPresentationWorkbenchAdvisor;
-import org.eclipse.rwt.lifecycle.IEntryPoint;
+import org.eclipse.rwt.lifecycle.*;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkbenchPreferenceConstants;
import org.eclipse.ui.PlatformUI;
@@ -26,6 +29,9 @@
private static final String DEMO_PRESENTATION
= "org.eclipse.rap.demo.presentation";
+ public static final int EVENT_CODE_REDIRECT = 2;
+ protected static final String JS_SEND_REDIRECT = "org.eclipse.swt.Request.getInstance().redirect(''{0}'');";
+
public int createUI() {
ScopedPreferenceStore prefStore
= ( ScopedPreferenceStore )PrefUtil.getAPIPreferenceStore();
@@ -39,6 +45,30 @@
}
Display display = PlatformUI.createDisplay();
- return PlatformUI.createAndRunWorkbench( display, worbenchAdvisor );
+
+ UICallBack.activate("callback_id");
+
+ UICallBack.setCallBackListener(new CallBackListener()
+ {
+ public void handleCallBack(CallBackEvent event) throws IOException
+ {
+ if (event.code == EVENT_CODE_REDIRECT)
+ {
+ String result = MessageFormat.format(JS_SEND_REDIRECT,
+ new Object[] { event.data });
+ event.dest.writeJSResponse(result);
+ event.doit = false;
+ }
+ }
+ });
+
+ try
+ {
+ return PlatformUI.createAndRunWorkbench( display, worbenchAdvisor );
+ }
+ finally
+ {
+ UICallBack.deactivate("callback_id");
+ }
}
}
Index: src/org/eclipse/rap/demo/actions/RedirectAction.java
===================================================================
RCS file: src/org/eclipse/rap/demo/actions/RedirectAction.java
diff -N src/org/eclipse/rap/demo/actions/RedirectAction.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/rap/demo/actions/RedirectAction.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2009 EclipseSource and others. 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:
+ * EclipseSource - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rap.demo.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.rap.demo.DemoWorkbench;
+import org.eclipse.rwt.lifecycle.CallBackEvent;
+import org.eclipse.rwt.lifecycle.UICallBack;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+
+
+public class RedirectAction implements IWorkbenchWindowActionDelegate {
+
+ public void dispose() {
+ }
+
+ public void init( IWorkbenchWindow window ) {
+ }
+
+ public void run( IAction action ) {
+ CallBackEvent event = new CallBackEvent(DemoWorkbench.EVENT_CODE_REDIRECT);
+ event.data = "about:blank";
+ UICallBack.sendEvent(event);
+ }
+
+ public void selectionChanged( IAction action, ISelection selection ) {
+ }
+}