]> git.argeo.org Git - gpl/argeo-suite.git/blobdiff - swt/org.argeo.app.swt/src/org/argeo/app/swt/ux/SwtArgeoApp.java
Fix concurrent modification exception when cleaning up UIs
[gpl/argeo-suite.git] / swt / org.argeo.app.swt / src / org / argeo / app / swt / ux / SwtArgeoApp.java
index e733e8a29626762c6011a789d1a191b359b1fb39..9d3a19218017f87b48048478ec9333eaf5da49b4 100644 (file)
@@ -128,36 +128,52 @@ 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");
 
                long janitorPeriod = 60 * 60 * 1000;// 1h
+               // long janitorPeriod = 60 * 1000;// min
                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());
+                               try {
+                                       // copy Map in order to avoid concurrent modification exception
+                                       Iterator<Map.Entry<String, WeakReference<SwtAppUi>>> uiRefs = new HashMap<>(managedUis).entrySet()
+                                                       .iterator();
+                                       refs: while (uiRefs.hasNext()) {
+                                               Map.Entry<String, WeakReference<SwtAppUi>> entry = uiRefs.next();
+                                               String uiUuid = entry.getKey();
+                                               WeakReference<SwtAppUi> uiRef = entry.getValue();
+                                               SwtAppUi ui = uiRef.get();
+                                               if (ui == null) {
+                                                       if (log.isTraceEnabled())
+                                                               log.warn("Unreferenced UI " + uiUuid + " in " + appPid + ", removing it");
+                                                       managedUis.remove(uiUuid);
+                                                       continue refs;
+                                               }
+                                               if (!ui.isDisposed() && !ui.getDisplay().isDisposed()) {
+                                                       if (ui.isTimedOut()) {
+                                                               if (log.isTraceEnabled())
+                                                                       log.trace("Killing timed-out UI " + uiUuid + " in " + appPid);
+                                                               UiContext.killDisplay(ui.getDisplay());
+                                                       }
+                                               } else {
+                                                       if (log.isTraceEnabled())
+                                                               log.warn("Disposed UI " + uiUuid + " still referenced in " + appPid + ", removing it");
+                                                       managedUis.remove(uiUuid);
+                                               }
                                        }
+                                       if (log.isTraceEnabled())
+                                               log.trace(managedUis.size() + " UIs being managed by app " + appPid);
+                               } catch (Exception e) {
+                                       log.error("Could not clean up timed-out UIs", e);
                                }
-                               if (log.isTraceEnabled())
-                                       log.trace(managedUis.size() + " UIs being managed by app " + appPid);
                        }
                }, janitorPeriod, janitorPeriod);
 
+               if (log.isDebugEnabled())
+                       log.info("Argeo Suite App " + appPid + " started");
        }
 
        public void stop(Map<String, Object> properties) {
@@ -197,6 +213,7 @@ public class SwtArgeoApp extends AbstractArgeoApp implements CmsEventSubscriber
                SwtAppUi argeoSuiteUi = new SwtAppUi(uiParent, SWT.INHERIT_DEFAULT);
                // TODO make timeout configurable
                argeoSuiteUi.setUiTimeout(6 * 60 * 60 * 1000);// 6 hours
+               // argeoSuiteUi.setUiTimeout(60 * 1000);// 1 min
                String uid = cmsView.getUid();
                argeoSuiteUi.addDisposeListener(new CleanUpUi(uid));
                managedUis.put(uid, new WeakReference<>(argeoSuiteUi));
@@ -421,39 +438,12 @@ public class SwtArgeoApp extends AbstractArgeoApp implements CmsEventSubscriber
 //             }
        }
 
-//     private static String listTypes(Node context) {
-//             try {
-//                     StringBuilder sb = new StringBuilder();
-//                     sb.append(context.getPrimaryNodeType().getName());
-//                     for (NodeType superType : context.getPrimaryNodeType().getDeclaredSupertypes()) {
-//                             sb.append(' ');
-//                             sb.append(superType.getName());
-//                     }
-//
-//                     for (NodeType nodeType : context.getMixinNodeTypes()) {
-//                             sb.append(' ');
-//                             sb.append(nodeType.getName());
-//                             if (nodeType.getName().equals(EntityType.local.get()))
-//                                     sb.append('/').append(context.getProperty(EntityNames.ENTITY_TYPE).getString());
-//                             for (NodeType superType : nodeType.getDeclaredSupertypes()) {
-//                                     sb.append(' ');
-//                                     sb.append(superType.getName());
-//                             }
-//                     }
-//                     return sb.toString();
-//             } catch (RepositoryException e) {
-//                     throw new JcrException(e);
-//             }
-//     }
-
        @Override
        public void setState(CmsUi cmsUi, String state) {
                AppUi ui = (AppUi) cmsUi;
                if (state == null)
                        return;
                if (!state.startsWith("/")) {
-//                     if (cmsUi instanceof SwtAppUi) {
-//                             SwtAppUi ui = (SwtAppUi) cmsUi;
                        if (LOGIN.equals(state)) {
                                String appTitle = "";
                                if (ui.getTitle() != null)
@@ -466,10 +456,8 @@ public class SwtArgeoApp extends AbstractArgeoApp implements CmsEventSubscriber
                        properties.put(SuiteUxEvent.LAYER, layerId);
                        properties.put(SuiteUxEvent.CONTENT_PATH, HOME_STATE);
                        ui.getCmsView().sendEvent(SuiteUxEvent.switchLayer.topic(), properties);
-//                     }
                        return;
                }
-//             SwtAppUi suiteUi = (SwtAppUi) cmsUi;
                if (ui.isLoginScreen()) {
                        return;
                }
@@ -539,7 +527,7 @@ public class SwtArgeoApp extends AbstractArgeoApp implements CmsEventSubscriber
                                        ui.getCmsView().stateChanged(nodeToState(node), stateTitle(appTitle, CmsUxUtils.getTitle(node)));
                                } else if (isTopic(topic, SuiteUxEvent.switchLayer)) {
                                        String layerId = get(event, SuiteUxEvent.LAYER);
-                                       if (layerId != null) {
+                                       if (layerId != null && !"".equals(layerId.trim())) {
                                                SwtAppLayer suiteLayer = findLayer(layerId);
                                                if (suiteLayer == null)
                                                        throw new IllegalArgumentException("No layer '" + layerId + "' available.");