Skip to main content

[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 ) {
+  }
+}

Back to the top