From e9a4ad659e7d8c5eefc6df3b5415607f1a244ac2 Mon Sep 17 00:00:00 2001
From: Nils Christian Ehmke <nie@informatik.uni-kiel.de>
Date: Thu, 29 Nov 2012 21:22:57 +0100
Subject: [PATCH] Made the autolayout threadsafe.

---
 .../common/layout/GraphFlowLayouter.java      | 126 +++++++++---------
 .../view/CurrentAnalysisEditorGraphBean.java  |  32 +++--
 2 files changed, 83 insertions(+), 75 deletions(-)

diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/layout/GraphFlowLayouter.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/layout/GraphFlowLayouter.java
index 780fca4b..03ed18fa 100644
--- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/layout/GraphFlowLayouter.java
+++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/layout/GraphFlowLayouter.java
@@ -19,10 +19,6 @@ package kieker.webgui.common.layout;
 import java.util.ArrayList;
 import java.util.List;
 
-import kieker.webgui.common.exception.InvalidInputSizeException;
-import kieker.webgui.common.exception.UninitializedGraphException;
-
-
 import de.cau.cs.kieler.core.alg.BasicProgressMonitor;
 import de.cau.cs.kieler.core.alg.IKielerProgressMonitor;
 import de.cau.cs.kieler.core.kgraph.KEdge;
@@ -38,6 +34,9 @@ import de.cau.cs.kieler.kiml.options.PortConstraints;
 import de.cau.cs.kieler.kiml.util.KimlUtil;
 import de.cau.cs.kieler.klay.layered.LayeredLayoutProvider;
 
+import kieker.webgui.common.exception.InvalidInputSizeException;
+import kieker.webgui.common.exception.UninitializedGraphException;
+
 import org.eclipse.emf.common.util.EList;
 
 /**
@@ -49,15 +48,6 @@ import org.eclipse.emf.common.util.EList;
  */
 public final class GraphFlowLayouter {
 
-	/**
-	 * An array containing the child node and the ports from left to right.
-	 */
-	private static List<Object>[] children;
-	/**
-	 * An array containing edges. This way we can return edge information in the same order.
-	 */
-	private static KEdge[] edges;
-
 	/**
 	 * Private constructor as this is a utility class.
 	 */
@@ -73,16 +63,11 @@ public final class GraphFlowLayouter {
 	 * @return The constructed Graph
 	 * @throws InvalidInputSizeException
 	 */
-	private static KNode addNodes(final String input) throws InvalidInputSizeException {
-		final String[] positions = input.split(" ");
-
-		// set up root
-		final KNode graph = KimlUtil.createInitializedNode();
-		graph.getData(KShapeLayout.class).setProperty(LayoutOptions.EDGE_ROUTING, EdgeRouting.ORTHOGONAL);
+	private static void addNodes(final String[] positions, final LayoutInformation layoutInformation) throws InvalidInputSizeException {
+		layoutInformation.graph.getData(KShapeLayout.class).setProperty(LayoutOptions.EDGE_ROUTING, EdgeRouting.ORTHOGONAL);
 
 		// prepare array of lists
 		List<Object> child;
-		GraphFlowLayouter.children = new ArrayList[positions.length / 2];
 
 		final int dimHalf = Integer.parseInt(positions[0]);
 		final int dim = dimHalf * 2;
@@ -112,10 +97,10 @@ public final class GraphFlowLayouter {
 
 			// create Node
 			node = KimlUtil.createInitializedNode();
-			node.setParent(graph);
+			node.setParent(layoutInformation.graph);
 
 			child = new ArrayList<Object>();
-			GraphFlowLayouter.children[i] = child;
+			layoutInformation.children[i] = child;
 			child.add(node);
 
 			// set node dimensions
@@ -158,8 +143,6 @@ public final class GraphFlowLayouter {
 			}
 			i++;
 		}
-
-		return graph;
 	}
 
 	/**
@@ -180,20 +163,15 @@ public final class GraphFlowLayouter {
 	 * @throws InvalidInputSizeException
 	 *             If the input size is invalid.
 	 */
-	private static void addEdges(final String input) throws UninitializedGraphException, InvalidInputSizeException {
-		final String[] edgeInfo = input.split(" ");
-
+	private static void addEdges(final String[] edgeInfo, final LayoutInformation layoutInformation) throws UninitializedGraphException, InvalidInputSizeException {
 		// cannot add edges if no graph was constructed
-		if (GraphFlowLayouter.children == null) {
+		if (layoutInformation.children == null) {
 			throw new UninitializedGraphException();
 		}
 		if ((edgeInfo.length % 4) != 0) {
 			throw new InvalidInputSizeException();
 		}
 
-		// init edge Array
-		GraphFlowLayouter.edges = new KEdge[edgeInfo.length / 4];
-
 		// set up loop variables
 		KEdge edge;
 		int sourceID;
@@ -208,13 +186,13 @@ public final class GraphFlowLayouter {
 			// read from String
 			sourceID = Integer.parseInt(edgeInfo[e++]);
 			targetID = Integer.parseInt(edgeInfo[e++]);
-			sourcePort = (KPort) GraphFlowLayouter.children[sourceID].get(1 + Integer.parseInt(edgeInfo[e++]));
-			targetPort = (KPort) GraphFlowLayouter.children[targetID].get(1 + Integer.parseInt(edgeInfo[e++]));
+			sourcePort = (KPort) layoutInformation.children[sourceID].get(1 + Integer.parseInt(edgeInfo[e++]));
+			targetPort = (KPort) layoutInformation.children[targetID].get(1 + Integer.parseInt(edgeInfo[e++]));
 
 			// add edge to graph
 			edge = KimlUtil.createInitializedEdge();
-			edge.setSource((KNode) GraphFlowLayouter.children[sourceID].get(0));
-			edge.setTarget((KNode) GraphFlowLayouter.children[targetID].get(0));
+			edge.setSource((KNode) layoutInformation.children[sourceID].get(0));
+			edge.setTarget((KNode) layoutInformation.children[targetID].get(0));
 
 			// set ports of edge
 			edge.setSourcePort(sourcePort);
@@ -222,11 +200,24 @@ public final class GraphFlowLayouter {
 			edge.setTargetPort(targetPort);
 			targetPort.getEdges().add(edge);
 
-			GraphFlowLayouter.edges[ea++] = edge;
+			layoutInformation.edges[ea++] = edge;
 		}
 
 	}
 
+	private static LayoutInformation assembleLayoutInformation(final String nodesStr, final String edgesStr) {
+		final String[] edgeInfo = edgesStr.split(" ");
+		final String[] positions = nodesStr.split(" ");
+		final ArrayList[] children = new ArrayList[positions.length / 2];
+		final KEdge[] edges = new KEdge[edgeInfo.length / 4];
+		final LayoutInformation layoutInformation = new LayoutInformation(KimlUtil.createInitializedNode(), children, edges);
+
+		GraphFlowLayouter.addNodes(positions, layoutInformation);
+		GraphFlowLayouter.addEdges(edgeInfo, layoutInformation);
+
+		return layoutInformation;
+	}
+
 	/**
 	 * This method takes two Strings, describing some basic graph information, and constructs a KGraph, which is then layouted by a Kieler algorithm.
 	 * 
@@ -236,34 +227,21 @@ public final class GraphFlowLayouter {
 	 *            A String containing connection information of edges.
 	 * @return A String of space separated node positions.
 	 */
-	public static String layoutGraph(final String nodes, final String edges) {
-		KNode graph;
-		try {
-			graph = GraphFlowLayouter.addNodes(nodes);
-			GraphFlowLayouter.addEdges(edges);
-		} catch (final InvalidInputSizeException ie) {
-			System.err.println(ie.getMessage());
-			return null;
-		} catch (final UninitializedGraphException ue) {
-			System.err.println(ue.getMessage());
-			return null;
-		}
+	public static String layoutGraph(final String nodes, final String edges) throws UninitializedGraphException, InvalidInputSizeException {
+		final LayoutInformation layoutInformation = GraphFlowLayouter.assembleLayoutInformation(nodes, edges);
 
-		// create a progress monitor
+		// Create a progress monitor
 		final IKielerProgressMonitor progressMonitor = new BasicProgressMonitor();
 
-		// create the layout provider
+		// Create the layout provider
 		final AbstractLayoutProvider layoutProvider = new LayeredLayoutProvider();
 
-		// perform layout on the created graph
-		layoutProvider.doLayout(graph, progressMonitor);
-
-		// output layout information
-		// GraphFlowLayouter.printLayoutInfo(graph);
+		// Perform layout on the created graph
+		layoutProvider.doLayout(layoutInformation.graph, progressMonitor);
 
 		// convert layouted graph positions to String
-		final String layoutedGraph = GraphFlowLayouter.getPositions(graph);
-		final String bendPoints = GraphFlowLayouter.getBendPoints();
+		final String layoutedGraph = GraphFlowLayouter.getPositions(layoutInformation);
+		final String bendPoints = GraphFlowLayouter.getBendPoints(layoutInformation);
 		return layoutedGraph + "#" + bendPoints;
 	}
 
@@ -274,11 +252,11 @@ public final class GraphFlowLayouter {
 	 *            The graph with at least one child
 	 * @return The constructed string
 	 */
-	private static String getPositions(final KNode graph) {
+	private static String getPositions(final LayoutInformation layoutInformation) {
 		final StringBuilder sb = new StringBuilder();
 		KShapeLayout layout;
 
-		for (final KNode node : graph.getChildren()) {
+		for (final KNode node : layoutInformation.graph.getChildren()) {
 			layout = node.getData(KShapeLayout.class);
 			final int x = Math.round(layout.getXpos() + (layout.getWidth() / 2));
 			final int y = Math.round(layout.getYpos() + (layout.getHeight() / 2));
@@ -292,15 +270,17 @@ public final class GraphFlowLayouter {
 	}
 
 	/**
-	 * Iterates all edges and creates a semicolon separated String which contains bend points of all edges.
+	 * This method iterates through all edges of the given object and creates a semicolon separated String containing bend points of all edges.
 	 * 
-	 * @return The bend point String
+	 * @param layoutInformation
+	 *            The object containing the information about the graph and the layout.
+	 * @return The string containing the bend points.
 	 */
-	private static String getBendPoints() {
+	private static String getBendPoints(final LayoutInformation layoutInformation) {
 		final StringBuilder sb = new StringBuilder();
 
 		// iterate edges
-		for (final KEdge edge : GraphFlowLayouter.edges) {
+		for (final KEdge edge : layoutInformation.edges) {
 			final KEdgeLayout layout = edge.getData(KEdgeLayout.class);
 			final EList<KPoint> bendPoints = layout.getBendPoints();
 
@@ -318,4 +298,24 @@ public final class GraphFlowLayouter {
 
 		return sb.toString();
 	}
+
+	private static class LayoutInformation {
+
+		public final KNode graph;
+		/**
+		 * An array containing the child node and the ports from left to right.
+		 */
+		public final List<Object>[] children;
+		/**
+		 * An array containing edges. This way we can return edge information in the same order.
+		 */
+		public final KEdge[] edges;
+
+		public LayoutInformation(final KNode graph, final List<Object>[] children, final KEdge[] edges) {
+			this.graph = graph;
+			this.children = children;
+			this.edges = edges;
+		}
+
+	}
 }
diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentAnalysisEditorGraphBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentAnalysisEditorGraphBean.java
index 1dfaffb0..39a9ae0b 100644
--- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentAnalysisEditorGraphBean.java
+++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentAnalysisEditorGraphBean.java
@@ -34,6 +34,8 @@ import kieker.analysis.model.analysisMetaModel.MIRepositoryConnector;
 import kieker.common.logging.Log;
 import kieker.common.logging.LogFactory;
 import kieker.monitoring.core.registry.Registry;
+import kieker.webgui.common.exception.InvalidInputSizeException;
+import kieker.webgui.common.exception.UninitializedGraphException;
 import kieker.webgui.common.layout.GraphFlowLayouter;
 
 import org.primefaces.context.RequestContext;
@@ -205,18 +207,24 @@ public final class CurrentAnalysisEditorGraphBean {
 	 * This method uses the given parameters (via request parameter map) to calculate a new layout for the graph and use this layout.
 	 */
 	public synchronized void autoLayout() {
-		// Get the parameters
-		final Map<String, String> paramMap = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
-
-		final String nodes = paramMap.get("nodes");
-		final String edges = paramMap.get("edges");
-
-		// Calculate the layout
-		final String newLayout = GraphFlowLayouter.layoutGraph(nodes, edges);
-
-		// Now use it
-		RequestContext.getCurrentInstance().execute(String.format(CurrentAnalysisEditorGraphBean.JS_CMD_LOAD_FROM_LAYOUT, newLayout));
-		RequestContext.getCurrentInstance().execute(CurrentAnalysisEditorGraphBean.JS_CMD_REFRESH_GRAPH);
+		try {
+			// Get the parameters
+			final Map<String, String> paramMap = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
+
+			final String nodes = paramMap.get("nodes");
+			final String edges = paramMap.get("edges");
+
+			// Calculate the layout
+			final String newLayout = GraphFlowLayouter.layoutGraph(nodes, edges);
+
+			// Now use it
+			RequestContext.getCurrentInstance().execute(String.format(CurrentAnalysisEditorGraphBean.JS_CMD_LOAD_FROM_LAYOUT, newLayout));
+			RequestContext.getCurrentInstance().execute(CurrentAnalysisEditorGraphBean.JS_CMD_REFRESH_GRAPH);
+		} catch (final UninitializedGraphException ex) {
+			CurrentAnalysisEditorGraphBean.LOG.warn("Autolayout failed.", ex);
+		} catch (final InvalidInputSizeException ex) {
+			CurrentAnalysisEditorGraphBean.LOG.warn("Autolayout failed.", ex);
+		}
 	}
 
 	/**
-- 
GitLab