[549054] Optimize refreshAllElementVisibility.

Compute each mapping active parent layers only once during visibility
refresh of all elements.

Bug: 549054
Change-Id: Iafd1ac4950fdf1e5280b303f7f16f5265df1c3c0
Signed-off-by: Maxime Porhel <maxime.porhel@obeo.fr>
diff --git a/plugins/org.eclipse.sirius.diagram/src-core/org/eclipse/sirius/diagram/business/internal/helper/display/DisplayServiceImpl.java b/plugins/org.eclipse.sirius.diagram/src-core/org/eclipse/sirius/diagram/business/internal/helper/display/DisplayServiceImpl.java
index ce49e0c..41700cc 100644
--- a/plugins/org.eclipse.sirius.diagram/src-core/org/eclipse/sirius/diagram/business/internal/helper/display/DisplayServiceImpl.java
+++ b/plugins/org.eclipse.sirius.diagram/src-core/org/eclipse/sirius/diagram/business/internal/helper/display/DisplayServiceImpl.java
@@ -78,6 +78,7 @@
 
         try {
             EqualityHelper.setUriFragmentCacheEnabled(true);
+            LayerHelper.setActiveParentLayersCacheEnabled(mappingManager, true);
             NotificationUtil.sendNotification(diagram, Notification.Kind.START, Notification.REFRESH_VISIBILITY_ON_DIAGRAM);
             DslCommonPlugin.PROFILER.startWork(SiriusTasksKey.IS_VISIBLE_KEY);
             for (final DDiagramElement diagramElement : diagram.getDiagramElements()) {
@@ -91,7 +92,9 @@
         } finally {
             deactivateCache();
             EqualityHelper.setUriFragmentCacheEnabled(false);
+            LayerHelper.setActiveParentLayersCacheEnabled(mappingManager, false);
         }
+
     }
 
     /**
diff --git a/plugins/org.eclipse.sirius.diagram/src-core/org/eclipse/sirius/diagram/business/internal/metamodel/helper/LayerHelper.java b/plugins/org.eclipse.sirius.diagram/src-core/org/eclipse/sirius/diagram/business/internal/metamodel/helper/LayerHelper.java
index a91b4e5..a6e8152 100644
--- a/plugins/org.eclipse.sirius.diagram/src-core/org/eclipse/sirius/diagram/business/internal/metamodel/helper/LayerHelper.java
+++ b/plugins/org.eclipse.sirius.diagram/src-core/org/eclipse/sirius/diagram/business/internal/metamodel/helper/LayerHelper.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2018 THALES GLOBAL SERVICES.
+ * Copyright (c) 2008, 2019 THALES GLOBAL SERVICES.
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -18,7 +18,9 @@
 import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 import org.eclipse.emf.common.util.BasicEList;
 import org.eclipse.emf.common.util.EList;
@@ -58,6 +60,8 @@
  */
 public final class LayerHelper {
 
+    private static final Map<DiagramMappingsManager, Map<DiagramElementMapping, Collection<Layer>>> ACTIVE_PARENT_LAYER_CACHE = new ConcurrentHashMap<>();
+
     /**
      * Avoid instantiation.
      */
@@ -165,21 +169,21 @@
     /**
      * Check if a diagram element is in an activated layer or not and visible.
      * 
-     * @param session
-     *            the current session.
+     * @param mappingsManager
+     *            the DiagramMappingsManager of the current diagram.
      * @param element
      *            the diagram element.
      * @return <code>true</code> if it is, <code>false</code> otherwise
      */
-    public static boolean isInActivatedLayer(DiagramMappingsManager session, final DDiagramElement element) {
-        return isInActivatedLayer(session, element, element.getParentDiagram());
+    public static boolean isInActivatedLayer(DiagramMappingsManager mappingsManager, final DDiagramElement element) {
+        return isInActivatedLayer(mappingsManager, element, element.getParentDiagram());
     }
 
     /**
      * Check if a diagram element is in an activated layer or not and visible.
      * 
-     * @param session
-     *            the current session.
+     * @param mappingsManager
+     *            the DiagramMappingsManager of the current diagram.
      * @param element
      *            the diagram element.
      * @param parentDiagram
@@ -190,7 +194,7 @@
      *            hierarchy of diagram element.
      * @return <code>true</code> if it is, <code>false</code> otherwise
      */
-    public static boolean isInActivatedLayer(DiagramMappingsManager session, final DDiagramElement element, final DDiagram parentDiagram) {
+    public static boolean isInActivatedLayer(DiagramMappingsManager mappingsManager, final DDiagramElement element, final DDiagram parentDiagram) {
         final DiagramElementMapping mapping = element.getDiagramElementMapping();
 
         if (!LayerHelper.withoutLayersMode(mapping)) {
@@ -202,7 +206,7 @@
             }
 
             boolean visible = false;
-            if (diagram != null && session.getActiveParentLayers(mapping).size() > 0) {
+            if (diagram != null && getActiveParentLayers(mappingsManager, mapping).size() > 0) {
                 /*
                  * We are visible in the following cases: 1. the mapping is in active layer and not hidden by owner
                  * mapping in an active layer and container is diagram 2- the mapping is in active layer and not hidden
@@ -217,13 +221,13 @@
                 final EObject registryMappingInstance = ViewpointRegistry.getInstance().find(mapping);
                 final Collection<Setting> settings = ViewpointRegistry.getInstance().getCrossReferencer().getInverseReferences(registryMappingInstance, true);
 
-                if (!LayerHelper.hideSubMappingsInImporters(session, diagram, settings, mapping)) {
+                if (!LayerHelper.hideSubMappingsInImporters(mappingsManager, diagram, settings, mapping)) {
                     final EObject container = element.eContainer();
 
                     /*
                      * Case 2 The mapping should be imported by another mapping owned by a visible element.
                      */
-                    if (container instanceof DDiagramElement && LayerHelper.isInActivatedLayer(session, (DDiagramElement) container, parentDiagram)) {
+                    if (container instanceof DDiagramElement && LayerHelper.isInActivatedLayer(mappingsManager, (DDiagramElement) container, parentDiagram)) {
                         visible = LayerHelper.caseDiagramElementContainer((DDiagramElement) container, mapping);
                     }
                     /*
@@ -306,27 +310,27 @@
     /**
      * Check if a diagram element mapping is in an activated layer or not.
      * 
-     * @param session
-     *            the current session.
+     * @param mappingsManager
+     *            the DiagramMappingsManager of the current diagram.
      * @param mapping
      *            the diagram element mapping.
      * @param diagram
      *            the diagram.
      * @return <code>true</code> if it is, <code>false</code> otherwise
      */
-    public static boolean isInActivatedLayer(DiagramMappingsManager session, final DDiagram diagram, final DiagramElementMapping mapping) {
+    public static boolean isInActivatedLayer(DiagramMappingsManager mappingsManager, final DDiagram diagram, final DiagramElementMapping mapping) {
         if (!LayerHelper.withoutLayersMode(mapping)) {
 
             boolean visible = false;
 
-            final Collection<Layer> layers = session.getActiveParentLayers(mapping);
+            final Collection<Layer> layers = getActiveParentLayers(mappingsManager, mapping);
             for (final Layer layer : layers) {
                 if (EqualityHelper.contains(diagram.getActivatedLayers(), layer)) {
 
                     final EObject registryMappingInstance = ViewpointRegistry.getInstance().find(mapping);
                     final Collection<Setting> settings = ViewpointRegistry.getInstance().getCrossReferencer().getInverseReferences(registryMappingInstance);
 
-                    if (!LayerHelper.hideSubMappingsInImporters(session, diagram, settings, mapping)) {
+                    if (!LayerHelper.hideSubMappingsInImporters(mappingsManager, diagram, settings, mapping)) {
                         visible = true;
                         break;
                     }
@@ -338,6 +342,40 @@
     }
 
     /**
+     * Enable or disable the ability to cache the computed parent layers for the given DiagramMappingManager. The cache
+     * is cleared when this method is called to disable the cache.
+     * 
+     * @param mappingsManager
+     *            DiagramMappingsManager of the current diagram.
+     * @param enable
+     *            <code>true</code> to allow this helper to put the computed active parent layers in a cache,
+     *            <code>false</code> otherwise.
+     */
+    public static synchronized void setActiveParentLayersCacheEnabled(DiagramMappingsManager mappingsManager, boolean enable) {
+        if (enable && !ACTIVE_PARENT_LAYER_CACHE.containsKey(mappingsManager)) {
+            ACTIVE_PARENT_LAYER_CACHE.put(mappingsManager, new ConcurrentHashMap<>());
+        }
+
+        if (!enable) {
+            ACTIVE_PARENT_LAYER_CACHE.remove(mappingsManager);
+        }
+    }
+
+    private static Collection<Layer> getActiveParentLayers(DiagramMappingsManager mappingsManager, final DiagramElementMapping mapping) {
+        Map<DiagramElementMapping, Collection<Layer>> managerCache = ACTIVE_PARENT_LAYER_CACHE.get(mappingsManager);
+        if (managerCache != null) {
+            Collection<Layer> cachedValue = managerCache.get(mapping);
+            if (cachedValue == null) {
+                cachedValue = mappingsManager.getActiveParentLayers(mapping);
+                managerCache.put(mapping, cachedValue);
+            }
+            return cachedValue;
+        }
+
+        return mappingsManager.getActiveParentLayers(mapping);
+    }
+
+    /**
      * Check if a diagram element mapping is in an activated layer or not.
      * 
      * @param mapping