Improve UI timeout
[gpl/argeo-suite.git] / swt / org.argeo.app.swt / src / org / argeo / app / swt / ux / SwtArgeoApp.java
index a81c33ef83f17fce709099e4fe52dc4293a563bf..e733e8a29626762c6011a789d1a191b359b1fb39 100644 (file)
@@ -2,14 +2,18 @@ package org.argeo.app.swt.ux;
 
 import static org.argeo.api.cms.ux.CmsView.CMS_VIEW_UID_PROPERTY;
 
+import java.lang.ref.WeakReference;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
 import java.util.TreeMap;
 import java.util.TreeSet;
 
@@ -91,7 +95,8 @@ public class SwtArgeoApp extends AbstractArgeoApp implements CmsEventSubscriber
 //     private CmsUserManager cmsUserManager;
 
        // TODO make more optimal or via CmsSession/CmsView
-       private Map<String, SwtAppUi> managedUis = Collections.synchronizedMap(new HashMap<>());
+       private static Timer janitorTimer = new Timer(true);
+       private Map<String, WeakReference<SwtAppUi>> managedUis = new HashMap<>();
 
        // ACR
        private ContentRepository contentRepository;
@@ -104,9 +109,6 @@ public class SwtArgeoApp extends AbstractArgeoApp implements CmsEventSubscriber
                        getCmsContext().getCmsEventBus().addEventSubscriber(event.topic(), this);
                }
 
-               if (log.isDebugEnabled())
-                       log.info("Argeo Suite App started");
-
                if (properties.containsKey(DEFAULT_UI_NAME_PROPERTY))
                        defaultUiName = LangUtils.get(properties, DEFAULT_UI_NAME_PROPERTY);
                if (properties.containsKey(DEFAULT_THEME_ID_PROPERTY))
@@ -126,25 +128,47 @@ public class SwtArgeoApp extends AbstractArgeoApp implements CmsEventSubscriber
                        // TODO does it make sense to accept that?
                        appPid = "<unknown>";
                }
+               if (log.isDebugEnabled())
+                       log.info("Argeo Suite App " + appPid + " started");
 
                Objects.requireNonNull(contentRepository, "Content repository must be provided");
                Objects.requireNonNull(appUserState, "App user state must be provided");
-//             if (pidPrefix == null)
-//                     throw new IllegalArgumentException("PID prefix must be set.");
 
-//             headerPid = pidPrefix + "header";
-//             footerPid = pidPrefix + "footer";
-//             leadPanePid = pidPrefix + "leadPane";
-//             adminLeadPanePid = pidPrefix + "adminLeadPane";
-//             loginScreenPid = pidPrefix + "loginScreen";
+               long janitorPeriod = 60 * 60 * 1000;// 1h
+               janitorTimer.schedule(new TimerTask() {
+
+                       @Override
+                       public void run() {
+                               Iterator<WeakReference<SwtAppUi>> uiRefs = managedUis.values().iterator();
+                               refs: while (uiRefs.hasNext()) {
+                                       WeakReference<SwtAppUi> uiRef = uiRefs.next();
+                                       SwtAppUi ui = uiRef.get();
+                                       if (ui == null) {
+                                               if (log.isTraceEnabled())
+                                                       log.warn("Unreferenced UI in " + appPid + ", removing it");
+                                               uiRefs.remove();
+                                               continue refs;
+                                       }
+                                       if (!ui.isDisposed() && !ui.getDisplay().isDisposed()) {
+                                               ui.getDisplay().asyncExec(() -> ui.disposeIfTimedout());
+                                       }
+                               }
+                               if (log.isTraceEnabled())
+                                       log.trace(managedUis.size() + " UIs being managed by app " + appPid);
+                       }
+               }, janitorPeriod, janitorPeriod);
 
        }
 
        public void stop(Map<String, Object> properties) {
-               for (SwtAppUi ui : managedUis.values())
+               refs: for (WeakReference<SwtAppUi> uiRef : managedUis.values()) {
+                       SwtAppUi ui = uiRef.get();
+                       if (ui == null)
+                               continue refs;
                        if (!ui.isDisposed() && !ui.getDisplay().isDisposed()) {
                                ui.getDisplay().syncExec(() -> ui.dispose());
                        }
+               }
                managedUis.clear();
                if (log.isDebugEnabled())
                        log.info("Argeo Suite App stopped");
@@ -171,9 +195,11 @@ public class SwtArgeoApp extends AbstractArgeoApp implements CmsEventSubscriber
                if (theme != null)
                        CmsSwtUtils.registerCmsTheme(uiParent.getShell(), theme);
                SwtAppUi argeoSuiteUi = new SwtAppUi(uiParent, SWT.INHERIT_DEFAULT);
+               // TODO make timeout configurable
+               argeoSuiteUi.setUiTimeout(6 * 60 * 60 * 1000);// 6 hours
                String uid = cmsView.getUid();
-               managedUis.put(uid, argeoSuiteUi);
                argeoSuiteUi.addDisposeListener(new CleanUpUi(uid));
+               managedUis.put(uid, new WeakReference<>(argeoSuiteUi));
                return argeoSuiteUi;
        }
 
@@ -590,7 +616,10 @@ public class SwtArgeoApp extends AbstractArgeoApp implements CmsEventSubscriber
        }
 
        private SwtAppUi getRelatedUi(Map<String, Object> eventProperties) {
-               return managedUis.get(get(eventProperties, CMS_VIEW_UID_PROPERTY));
+               WeakReference<SwtAppUi> uiRef = managedUis.get(get(eventProperties, CMS_VIEW_UID_PROPERTY));
+               if (uiRef == null)
+                       return null;
+               return uiRef.get();
        }
 
        public static String get(Map<String, Object> eventProperties, String key) {
@@ -672,14 +701,6 @@ public class SwtArgeoApp extends AbstractArgeoApp implements CmsEventSubscriber
                }
        }
 
-//     public void setCmsUserManager(CmsUserManager cmsUserManager) {
-//             this.cmsUserManager = cmsUserManager;
-//     }
-
-//     protected ContentRepository getContentRepository() {
-//             return contentRepository;
-//     }
-
        public void setContentRepository(ContentRepository contentRepository) {
                this.contentRepository = contentRepository;
        }
@@ -697,7 +718,6 @@ public class SwtArgeoApp extends AbstractArgeoApp implements CmsEventSubscriber
                final String uid;
 
                public CleanUpUi(String uid) {
-                       super();
                        this.uid = uid;
                }