Introduce UX scheduler
[lgpl/argeo-commons.git] / swt / org.argeo.cms.swt / src / org / argeo / cms / swt / AbstractSwtCmsView.java
index 2059803036f2ab476205564534f0203ed1bdde62..127be0856195fecf7b0d484a16e654030f6849c4 100644 (file)
@@ -1,28 +1,50 @@
 package org.argeo.cms.swt;
 
-import java.security.PrivilegedAction;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.Callable;
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
 import java.util.concurrent.ExecutionException;
 
 import javax.security.auth.Subject;
 import javax.security.auth.login.LoginContext;
 
+import org.argeo.api.cms.CmsApp;
 import org.argeo.api.cms.CmsEventBus;
+import org.argeo.api.cms.CmsLog;
 import org.argeo.api.cms.ux.CmsImageManager;
 import org.argeo.api.cms.ux.CmsUi;
 import org.argeo.api.cms.ux.CmsView;
 import org.argeo.api.cms.ux.UxContext;
-import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.CurrentUser;
+import org.argeo.cms.util.CurrentSubject;
 import org.eclipse.swt.widgets.Display;
 
 public abstract class AbstractSwtCmsView implements CmsView {
+       private final static CmsLog log = CmsLog.getLog(AbstractSwtCmsView.class);
+
+       /** A timer to be used to perform background UX tasks. */
+       private final static Timer uxTimer = new Timer(true);
+
+       static {
+               // purge every day
+               uxTimer.schedule(new TimerTask() {
+
+                       @Override
+                       public void run() {
+                               uxTimer.purge();
+                       }
+               }, 0, 24 * 60 * 60 * 1000);
+       }
+
        protected final String uiName;
 
        protected LoginContext loginContext;
        protected String state;
-       protected Throwable exception;
+//     protected Throwable exception;
        protected UxContext uxContext;
        protected CmsImageManager imageManager;
 
@@ -37,6 +59,8 @@ public abstract class AbstractSwtCmsView implements CmsView {
 
        public abstract CmsEventBus getCmsEventBus();
 
+       public abstract CmsApp getCmsApp();
+
        @Override
        public void sendEvent(String topic, Map<String, Object> properties) {
                if (properties == null)
@@ -45,20 +69,43 @@ public abstract class AbstractSwtCmsView implements CmsView {
                        throw new IllegalArgumentException("Property " + CMS_VIEW_UID_PROPERTY + " is set to another CMS view uid ("
                                        + properties.get(CMS_VIEW_UID_PROPERTY) + ") then " + uid);
                properties.put(CMS_VIEW_UID_PROPERTY, uid);
+
+               log.trace(() -> uid + ": send event to " + topic);
+
                getCmsEventBus().sendEvent(topic, properties);
+               // getCmsApp().onEvent(topic, properties);
        }
 
-       public <T> T doAs(PrivilegedAction<T> action) {
+//     public void runAs(Runnable runnable) {
+//             display.asyncExec(() -> doAs(Executors.callable(runnable)));
+//     }
+
+       public <T> T doAs(Callable<T> action) {
                try {
                        CompletableFuture<T> result = new CompletableFuture<>();
                        Runnable toDo = () -> {
-                               T res = Subject.doAs(getSubject(), action);
+                               log.trace(() -> uid + ": process doAs");
+                               Subject subject = CurrentSubject.current();
+                               T res;
+                               if (subject != null) {
+                                       assert subject == getSubject();
+                                       try {
+                                               res = action.call();
+                                       } catch (Exception e) {
+                                               throw new CompletionException("Failed to execute action for " + subject, e);
+                                       }
+                               } else {
+                                       res = CurrentSubject.callAs(getSubject(), action);
+                               }
                                result.complete(res);
                        };
                        if (Thread.currentThread() == display.getThread())
                                toDo.run();
-                       else
-                               display.syncExec(toDo);
+                       else {
+                               display.asyncExec(toDo);
+                               display.wake();
+                       }
+//                             throw new IllegalStateException("Must be called from UI thread");
                        return result.get();
                } catch (InterruptedException | ExecutionException e) {
                        throw new IllegalStateException("Cannot execute action ins CMS view " + uid, e);
@@ -107,4 +154,37 @@ public abstract class AbstractSwtCmsView implements CmsView {
                }
        }
 
+       @Override
+       public TimerTask schedule(Runnable task, long delay) {
+               TimerTask timerTask = newSwtUxTimerTask(task);
+               uxTimer.schedule(timerTask, delay);
+               return timerTask;
+       }
+
+       @Override
+       public TimerTask schedule(Runnable task, long delay, long period) {
+               TimerTask timerTask = newSwtUxTimerTask(task);
+               uxTimer.schedule(timerTask, delay, period);
+               return timerTask;
+       }
+
+       protected TimerTask newSwtUxTimerTask(Runnable todo) {
+               return new TimerTask() {
+
+                       @Override
+                       public void run() {
+                               synchronized (display) {
+                                       try {
+                                               if (!display.isDisposed()) {
+                                                       display.syncExec(() -> {
+                                                               todo.run();
+                                                       });
+                                               }
+                                       } catch (Exception e) {
+                                               log.error("Cannot run UX timer task", e);
+                                       }
+                               }
+                       }
+               };
+       }
 }