From e5467854471c891d790af6fd03fc51eee9d7b467 Mon Sep 17 00:00:00 2001
From: Nils Christian Ehmke <nie@informatik.uni-kiel.de>
Date: Sat, 1 Jun 2013 22:29:30 +0200
Subject: [PATCH] Further development of the cockpit.

---
 .../Timer-Counter-Example.kax                 |   4 +-
 .../common/ClassAndMethodContainer.java       |  10 +-
 .../kieker/webgui/domain/DisplayType.java     |   2 +-
 .../webgui/service/impl/utility/Analysis.java |   9 +-
 .../web/beans/view/CurrentCockpitBean.java    | 114 +++++++++++-------
 5 files changed, 83 insertions(+), 56 deletions(-)

diff --git a/Kieker.WebGUI/bin/data/Timer-Counter-Example/Timer-Counter-Example.kax b/Kieker.WebGUI/bin/data/Timer-Counter-Example/Timer-Counter-Example.kax
index 55b94b5a..069b4511 100644
--- a/Kieker.WebGUI/bin/data/Timer-Counter-Example/Timer-Counter-Example.kax
+++ b/Kieker.WebGUI/bin/data/Timer-Counter-Example/Timer-Counter-Example.kax
@@ -24,7 +24,7 @@
     <outputPorts name="currentEventCount"/>
     <displays name="Visual Counter Display"/>
     <displays name="Counter Display"/>
-    <displays name="Plot Counter Display"/>
+    <displays name="XYPlot Counter Display"/>
     <inputPorts name="inputEvents"/>
   </plugins>
   <plugins xsi:type="Filter" name="Timestamps Counter" classname="kieker.analysis.plugin.filter.forward.CountingFilter">
@@ -32,7 +32,7 @@
     <outputPorts name="currentEventCount"/>
     <displays name="Visual Counter Display"/>
     <displays name="Counter Display"/>
-    <displays name="Plot Counter Display"/>
+    <displays name="XYPlot Counter Display"/>
     <inputPorts name="inputEvents"/>
   </plugins>
   <views name="Counter View" description="No description available.">
diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/ClassAndMethodContainer.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/ClassAndMethodContainer.java
index 4b3a66f5..f3a83404 100644
--- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/ClassAndMethodContainer.java
+++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/ClassAndMethodContainer.java
@@ -23,7 +23,7 @@ import kieker.analysis.AnalysisControllerThread;
 import kieker.analysis.display.HtmlText;
 import kieker.analysis.display.Image;
 import kieker.analysis.display.PlainText;
-import kieker.analysis.display.Plot;
+import kieker.analysis.display.XYPlot;
 import kieker.analysis.display.annotation.Display;
 import kieker.analysis.plugin.AbstractPlugin;
 import kieker.analysis.plugin.annotation.InputPort;
@@ -63,6 +63,7 @@ public class ClassAndMethodContainer {
 	private Class<?> imageClass;
 	private Class<?> plainTextClass;
 	private Class<?> htmlTextClass;
+	private Class<?> xyPlotClass;
 
 	private Class<? extends Annotation> pluginAnnotationClass;
 	private Class<? extends Annotation> repositoryAnnotationClass;
@@ -71,7 +72,6 @@ public class ClassAndMethodContainer {
 	private Class<? extends Annotation> inputPortAnnotationClass;
 	private Class<? extends Annotation> repositoryPortAnnotationClass;
 	private Class<? extends Annotation> displayAnnotationClass;
-	private Class<?> plotClass;
 
 	/**
 	 * Creates a new instance of this class, using the given class loader.
@@ -100,7 +100,7 @@ public class ClassAndMethodContainer {
 			this.htmlTextClass = classLoader.loadClass(HtmlText.class.getName());
 			this.plainTextClass = classLoader.loadClass(PlainText.class.getName());
 			this.imageClass = classLoader.loadClass(Image.class.getName());
-			this.plotClass = classLoader.loadClass(Plot.class.getName());
+			this.xyPlotClass = classLoader.loadClass(XYPlot.class.getName());
 
 			// Now we load the more specific annotation classes
 			this.pluginAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(Plugin.class.getName());
@@ -195,8 +195,8 @@ public class ClassAndMethodContainer {
 		return this.logImplWebguiLoggingClass;
 	}
 
-	public Class<?> getPlotClass() {
-		return this.plotClass;
+	public Class<?> getXYPlotClass() {
+		return this.xyPlotClass;
 	}
 
 }
diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/DisplayType.java b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/DisplayType.java
index ad86a5ef..159a9287 100644
--- a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/DisplayType.java
+++ b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/DisplayType.java
@@ -24,7 +24,7 @@ package kieker.webgui.domain;
 public enum DisplayType {
 
 	/** Represents the plot display type. */
-	TYPE_PLOT,
+	TYPE_XY_PLOT,
 	/** Represents the plain text display type. */
 	TYPE_PLAIN_TEXT,
 	/** Represents the Html text display type. */
diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/utility/Analysis.java b/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/utility/Analysis.java
index 571e277b..7b60ea7e 100644
--- a/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/utility/Analysis.java
+++ b/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/utility/Analysis.java
@@ -231,15 +231,16 @@ public class Analysis {
 	 */
 	public DisplayType getDisplayType(final String viewName, final String displayConnectorName) {
 		final Object parameter = this.displayObjects.get(viewName).get(displayConnectorName);
-
-		if (parameter.getClass() == this.classAndMethodContainer.getImageClass()) {
+		if (parameter == null) {
+			return null;
+		} else if (parameter.getClass() == this.classAndMethodContainer.getImageClass()) {
 			return DisplayType.TYPE_IMAGE;
 		} else if (parameter.getClass() == this.classAndMethodContainer.getPlainTextClass()) {
 			return DisplayType.TYPE_PLAIN_TEXT;
 		} else if (parameter.getClass() == this.classAndMethodContainer.getHtmlTextClass()) {
 			return DisplayType.TYPE_HTML_TEXT;
-		} else if (parameter.getClass() == this.classAndMethodContainer.getPlotClass()) {
-			return DisplayType.TYPE_PLOT;
+		} else if (parameter.getClass() == this.classAndMethodContainer.getXYPlotClass()) {
+			return DisplayType.TYPE_XY_PLOT;
 		} else {
 			return null;
 		}
diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentCockpitBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentCockpitBean.java
index a5a60fcc..cb2b991c 100644
--- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentCockpitBean.java
+++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentCockpitBean.java
@@ -16,8 +16,8 @@
 
 package kieker.webgui.web.beans.view;
 
-import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 
 import javax.faces.application.Application;
 import javax.faces.application.FacesMessage;
@@ -257,25 +257,28 @@ public class CurrentCockpitBean {
 				if (this.projectService.getCurrentState(this.projectName) != null) {
 					final DisplayType displayType = this.projectService.getDisplayType(this.projectName, this.activeView.getName(), displayConnector.getName());
 
-					// Update the element depending on the display type
-					switch (displayType) {
-					case TYPE_PLAIN_TEXT:
-						this.updatePlainTextDisplay(component, displayConnector.getName());
-						break;
-					case TYPE_HTML_TEXT:
-						this.updateHTMLTextDisplay(component, displayConnector.getName());
-						break;
-					case TYPE_IMAGE:
-						this.updateImageDisplay(component, displayConnector.getName());
-						break;
-					case TYPE_PLOT:
-						this.updatePlotDisplay(component, displayConnector.getName());
-						break;
-					default:
-						// Unknown type
+					if (displayType != null) {
+						// Update the element depending on the display type
+						switch (displayType) {
+						case TYPE_PLAIN_TEXT:
+							this.updatePlainTextDisplay(component, displayConnector.getName());
+							break;
+						case TYPE_HTML_TEXT:
+							this.updateHTMLTextDisplay(component, displayConnector.getName());
+							break;
+						case TYPE_IMAGE:
+							this.updateImageDisplay(component, displayConnector.getName());
+							break;
+						case TYPE_XY_PLOT:
+							this.updateXYPlotDisplay(component, displayConnector.getName());
+							break;
+						default:
+							// Unknown type
+							this.updateDisplayWithDefaultContent(component);
+							break;
+						}
+					} else {
 						this.updateDisplayWithDefaultContent(component);
-						break;
-
 					}
 				} else {
 					// If the analysis has not yet been initialized, we add a simple note to each of the panels
@@ -366,12 +369,20 @@ public class CurrentCockpitBean {
 	}
 
 	private void updateDisplayWithDefaultContent(final UIComponent component) {
-		component.getChildren().clear();
+		final boolean isAlreadyCorrectlyInitialized = (component.getChildCount() == 1) && (component.getChildren().get(0) instanceof HtmlOutputText);
+		final HtmlOutputText htmlOutputText;
 
-		final HtmlOutputText htmlOutputText = new HtmlOutputText();
-		htmlOutputText.setValue("N/A");
+		// Avoid unnecessary component creation. Use the existing components if they are already existing and from the correct type.
+		if (isAlreadyCorrectlyInitialized) {
+			htmlOutputText = (HtmlOutputText) component.getChildren().get(0);
+		} else {
+			htmlOutputText = new HtmlOutputText();
 
-		component.getChildren().add(htmlOutputText);
+			component.getChildren().clear();
+			component.getChildren().add(htmlOutputText);
+		}
+
+		htmlOutputText.setValue("N/A");
 	}
 
 	private void updateHTMLTextDisplay(final UIComponent component, final String displayConnectorName) { // NOPMD (Not implemented yet)
@@ -385,15 +396,25 @@ public class CurrentCockpitBean {
 	}
 
 	private void updatePlainTextDisplay(final UIComponent component, final String displayConnectorName) {
-		try {
+		final boolean isAlreadyCorrectlyInitialized = (component.getChildCount() == 1) && (component.getChildren().get(0) instanceof HtmlOutputText);
+		final HtmlOutputText htmlOutputText;
+
+		// Avoid unnecessary component creation. Use the existing components if they are already existing and from the correct type.
+		if (isAlreadyCorrectlyInitialized) {
+			htmlOutputText = (HtmlOutputText) component.getChildren().get(0);
+		} else {
+			htmlOutputText = new HtmlOutputText();
+
 			component.getChildren().clear();
+			component.getChildren().add(htmlOutputText);
+		}
 
+		try {
 			final Object displayObject = this.projectService.getDisplay(this.projectName, this.activeView.getName(), displayConnectorName);
 			final String text = (String) new Mirror().on(displayObject).invoke().method("getText").withoutArgs();
-			final HtmlOutputText htmlOutputText = new HtmlOutputText();
+
 			htmlOutputText.setValue(text);
 
-			component.getChildren().add(htmlOutputText);
 		} catch (final DisplayNotFoundException ex) {
 			CurrentCockpitBean.LOG.warn("Display not found.", ex);
 			this.updateDisplayWithDefaultContent(component);
@@ -407,16 +428,19 @@ public class CurrentCockpitBean {
 	}
 
 	@SuppressWarnings("unchecked")
-	private void updatePlotDisplay(final UIComponent component, final String displayConnectorName) {
-		try {
-			component.getChildren().clear();
+	private void updateXYPlotDisplay(final UIComponent component, final String displayConnectorName) {
+		final boolean isAlreadyCorrectlyInitialized = (component.getChildCount() == 1) && (component.getChildren().get(0) instanceof LineChart);
 
+		final LineChartSeries lineChartSeries;
+
+		// Avoid unnecessary component creation. Use the existing components if they are already existing and from the correct type.
+		if (isAlreadyCorrectlyInitialized) {
+			final LineChart lineChart = (LineChart) component.getChildren().get(0);
+			lineChartSeries = (LineChartSeries) ((CartesianChartModel) lineChart.getValue()).getSeries().get(0);
+		} else {
 			final FacesContext facesContext = FacesContext.getCurrentInstance();
 			final Application application = facesContext.getApplication();
 
-			final Object displayObj = this.projectService.getDisplay(this.projectName, this.activeView.getName(), displayConnectorName);
-			final Collection<Long> entries = (Collection<Long>) new Mirror().on(displayObj).invoke().method("getEntries").withoutArgs();
-
 			// Create the Primefaces chart component
 			final LineChart lineChart = (LineChart) application.createComponent(facesContext, "org.primefaces.component.chart.LineChart",
 					"org.primefaces.component.chart.LineChartRenderer");
@@ -424,23 +448,25 @@ public class CurrentCockpitBean {
 
 			// Add the corresponding model
 			final CartesianChartModel linearModel = new CartesianChartModel();
-			final LineChartSeries series = new LineChartSeries();
+			lineChartSeries = new LineChartSeries();
+			lineChartSeries.setLabel("Series");
+
+			linearModel.addSeries(lineChartSeries);
+			lineChart.setValue(linearModel);
+
+			component.getChildren().clear();
+			component.getChildren().add(lineChart);
+		}
 
-			series.setLabel("Series");
+		try {
+			final Object displayObj = this.projectService.getDisplay(this.projectName, this.activeView.getName(), displayConnectorName);
+			final Map<Object, Number> entries = (Map<Object, Number>) new Mirror().on(displayObj).invoke().method("getEntries").withoutArgs();
 
 			if (entries.isEmpty()) {
-				series.set(0, 0);
+				lineChartSeries.set(0, 0);
 			} else {
-				int x = 0;
-				for (final Long entry : entries) {
-					series.set(x++, entry);
-				}
+				lineChartSeries.setData(entries);
 			}
-
-			linearModel.addSeries(series);
-			lineChart.setValue(linearModel);
-
-			component.getChildren().add(lineChart);
 		} catch (final DisplayNotFoundException ex) {
 			CurrentCockpitBean.LOG.warn("Display not found.", ex);
 			this.updateDisplayWithDefaultContent(component);
-- 
GitLab