From 4034008c1035cd0fd74bf80f9f5e1d1831056bcd Mon Sep 17 00:00:00 2001
From: Nils Christian Ehmke <nie@informatik.uni-kiel.de>
Date: Sun, 2 Jun 2013 11:20:40 +0200
Subject: [PATCH] Added the meter gauge display.

---
 .../Bookstore-Example/Bookstore-Example.kax   | 15 ++++-
 .../Timer-Counter-Example.kax                 |  6 +-
 .../bin/data/Timer-Counter-Example/meta.dat   |  6 +-
 .../common/ClassAndMethodContainer.java       |  7 +++
 .../kieker/webgui/domain/DisplayType.java     |  4 +-
 .../webgui/service/impl/utility/Analysis.java |  6 +-
 .../web/beans/view/CurrentCockpitBean.java    | 63 +++++++++++++++++++
 .../main/webapp/pages/ControllerPage.xhtml    |  2 +-
 .../Class2ModelInstanceConverterTest.java     |  2 +-
 9 files changed, 100 insertions(+), 11 deletions(-)

diff --git a/Kieker.WebGUI/bin/data/Bookstore-Example/Bookstore-Example.kax b/Kieker.WebGUI/bin/data/Bookstore-Example/Bookstore-Example.kax
index a48eb3ed..63d0692a 100644
--- a/Kieker.WebGUI/bin/data/Bookstore-Example/Bookstore-Example.kax
+++ b/Kieker.WebGUI/bin/data/Bookstore-Example/Bookstore-Example.kax
@@ -18,19 +18,28 @@
   <plugins xsi:type="Filter" name="Invalid Counter" classname="kieker.analysis.plugin.filter.forward.CountingFilter">
     <outputPorts name="relayedEvents" subscribers="//@plugins.2/@inputPorts.0"/>
     <outputPorts name="currentEventCount"/>
+    <displays name="Visual Counter Display"/>
     <displays name="Counter Display"/>
+    <displays name="XYPlot Counter Display"/>
+	<displays name="Meter Gauge Counter Display"/>
     <inputPorts name="inputEvents"/>
   </plugins>
   <plugins xsi:type="Filter" name="Valid Counter" classname="kieker.analysis.plugin.filter.forward.CountingFilter">
     <outputPorts name="relayedEvents" subscribers="//@plugins.6/@inputPorts.0"/>
     <outputPorts name="currentEventCount"/>
+    <displays name="Visual Counter Display"/>
     <displays name="Counter Display"/>
+    <displays name="XYPlot Counter Display"/>
+	<displays name="Meter Gauge Counter Display"/>
     <inputPorts name="inputEvents"/>
   </plugins>
   <plugins xsi:type="Filter" name="Global Counter" classname="kieker.analysis.plugin.filter.forward.CountingFilter">
     <outputPorts name="relayedEvents" subscribers="//@plugins.1/@inputPorts.0"/>
     <outputPorts name="currentEventCount"/>
+    <displays name="Visual Counter Display"/>
     <displays name="Counter Display"/>
+    <displays name="XYPlot Counter Display"/>
+	<displays name="Meter Gauge Counter Display"/>
     <inputPorts name="inputEvents"/>
   </plugins>
   <plugins xsi:type="Filter" name="Valid Printer" classname="kieker.examples.userguide.ch3and4bookstore.MyResponseTimeOutputPrinter">
@@ -40,9 +49,9 @@
   <dependencies filePath="BookstoreApplication.jar"/>
   <dependencies filePath="commons-cli-1.2.jar"/>
   <views name="Counter View" description="Shows the available counters">
-    <displayConnectors name="Invalid Counter" display="//@plugins.3/@displays.0"/>
-    <displayConnectors name="Invalid Counter" display="//@plugins.4/@displays.0"/>
-    <displayConnectors name="Global Counter" display="//@plugins.5/@displays.0"/>
+    <displayConnectors name="Invalid Counter" display="//@plugins.3/@displays.1"/>
+    <displayConnectors name="Invalid Counter" display="//@plugins.4/@displays.1"/>
+    <displayConnectors name="Global Counter" display="//@plugins.5/@displays.1"/>
   </views>
   <properties name="recordsTimeUnit" value="NANOSECONDS"/>
   <properties name="projectName" value="AnalysisProject"/>
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 069b4511..ac222a44 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
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Project xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="platform:/resource/Kieker/model/AnalysisMetaModel.ecore">
   <plugins xsi:type="Reader" name="TimeReader" classname="kieker.analysis.plugin.reader.timer.TimeReader">
-    <properties name="updateIntervalNS" value="2000000000"/>
+    <properties name="updateIntervalNS" value="1500000000"/>
     <properties name="delayNS" value="0"/>
     <properties name="blockingRead" value="true"/>
     <outputPorts name="timestamps" subscribers="//@plugins.4/@inputPorts.0"/>
@@ -25,6 +25,7 @@
     <displays name="Visual Counter Display"/>
     <displays name="Counter Display"/>
     <displays name="XYPlot Counter Display"/>
+    <displays name="Meter Gauge Counter Display"/>
     <inputPorts name="inputEvents"/>
   </plugins>
   <plugins xsi:type="Filter" name="Timestamps Counter" classname="kieker.analysis.plugin.filter.forward.CountingFilter">
@@ -33,6 +34,7 @@
     <displays name="Visual Counter Display"/>
     <displays name="Counter Display"/>
     <displays name="XYPlot Counter Display"/>
+    <displays name="Meter Gauge Counter Display"/>
     <inputPorts name="inputEvents"/>
   </plugins>
   <views name="Counter View" description="No description available.">
@@ -42,6 +44,8 @@
     <displayConnectors name="Timestamps (Image)" display="//@plugins.4/@displays.0"/>
     <displayConnectors name="Timestamps (Text)" display="//@plugins.4/@displays.1"/>
     <displayConnectors name="Timestamps (Plot)" display="//@plugins.4/@displays.2"/>
+    <displayConnectors name="Timestamp Records (Meter Gauge)" display="//@plugins.3/@displays.3"/>
+    <displayConnectors name="Timestamps (Meter Gauge)" display="//@plugins.4/@displays.3"/>
   </views>
   <views name="Only Records View" description="No description available.">
     <displayConnectors name="Timestamp Records" display="//@plugins.3/@displays.1"/>
diff --git a/Kieker.WebGUI/bin/data/Timer-Counter-Example/meta.dat b/Kieker.WebGUI/bin/data/Timer-Counter-Example/meta.dat
index eee45730..8fbfbb64 100644
--- a/Kieker.WebGUI/bin/data/Timer-Counter-Example/meta.dat
+++ b/Kieker.WebGUI/bin/data/Timer-Counter-Example/meta.dat
@@ -1,6 +1,6 @@
 #
-#Fri May 31 19:58:26 CEST 2013
+#Sun Jun 02 11:24:25 CEST 2013
 owner=admin
-cockpit\ layout=0 0 0 1 0 2 1 0 1 1 1 2 0 0 
 last\ user=admin
-analysis\ layout=id0 -615 -256 336 72;id1 -675 26 216 84;id2 59 -104 204 72;id3 59 26 204 72;id4 -305 38 396 84;id5 -305 -96 312 84;\#id1.0 id5.9 -535.5 25.5 -535.5 -84.5;id5.10 id2.2 -75.5 -96.5 -75.5 -92.5;
+cockpit\ layout=0 0 0 1 0 2 1 0 1 1 1 2 0 3 1 3 0 0 
+analysis\ layout=id0 -2221 -900 336 72;id1 -2281 -618 216 84;id2 -1547 -748 204 72;id3 -1547 -618 204 72;id4 -1911 -606 396 84;id5 -1911 -740 312 84;\#id1.0 id5.9 -2142.5 -619.5 -2142.5 -729.5;id5.10 id2.2 -1682.5 -741.5 -1682.5 -737.5;
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 f3a83404..9dab09ba 100644
--- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/ClassAndMethodContainer.java
+++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/ClassAndMethodContainer.java
@@ -22,6 +22,7 @@ import kieker.analysis.AnalysisController.AnalysisControllerWithMapping;
 import kieker.analysis.AnalysisControllerThread;
 import kieker.analysis.display.HtmlText;
 import kieker.analysis.display.Image;
+import kieker.analysis.display.MeterGauge;
 import kieker.analysis.display.PlainText;
 import kieker.analysis.display.XYPlot;
 import kieker.analysis.display.annotation.Display;
@@ -64,6 +65,7 @@ public class ClassAndMethodContainer {
 	private Class<?> plainTextClass;
 	private Class<?> htmlTextClass;
 	private Class<?> xyPlotClass;
+	private Class<?> meterGaugeClass;
 
 	private Class<? extends Annotation> pluginAnnotationClass;
 	private Class<? extends Annotation> repositoryAnnotationClass;
@@ -101,6 +103,7 @@ public class ClassAndMethodContainer {
 			this.plainTextClass = classLoader.loadClass(PlainText.class.getName());
 			this.imageClass = classLoader.loadClass(Image.class.getName());
 			this.xyPlotClass = classLoader.loadClass(XYPlot.class.getName());
+			this.meterGaugeClass = classLoader.loadClass(MeterGauge.class.getName());
 
 			// Now we load the more specific annotation classes
 			this.pluginAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(Plugin.class.getName());
@@ -199,4 +202,8 @@ public class ClassAndMethodContainer {
 		return this.xyPlotClass;
 	}
 
+	public Class<?> getMeterGaugeClass() {
+		return this.meterGaugeClass;
+	}
+
 }
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 159a9287..ec93aa5b 100644
--- a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/DisplayType.java
+++ b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/DisplayType.java
@@ -30,6 +30,8 @@ public enum DisplayType {
 	/** Represents the Html text display type. */
 	TYPE_HTML_TEXT,
 	/** Represents the image display type. */
-	TYPE_IMAGE
+	TYPE_IMAGE,
+	/** Represents the meter gauge display type. */
+	TYPE_METER_GAUGE
 
 }
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 7b60ea7e..919e3ae2 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
@@ -23,6 +23,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import kieker.analysis.AnalysisController;
 import kieker.common.logging.Log;
 import kieker.common.logging.LogFactory;
 import kieker.webgui.common.ClassAndMethodContainer;
@@ -198,7 +199,8 @@ public class Analysis {
 	 */
 	public Object[] getLogEntries() {
 		try {
-			return (Object[]) new Mirror().on(this.classAndMethodContainer.getLogImplWebguiLoggingClass()).invoke().method("getEntries").withoutArgs();
+			return (Object[]) new Mirror().on(this.classAndMethodContainer.getLogImplWebguiLoggingClass()).invoke().method("getEntries")
+					.withArgs(AnalysisController.class.getName());
 		} catch (final MirrorException ex) {
 			return new Object[0];
 		}
@@ -241,6 +243,8 @@ public class Analysis {
 			return DisplayType.TYPE_HTML_TEXT;
 		} else if (parameter.getClass() == this.classAndMethodContainer.getXYPlotClass()) {
 			return DisplayType.TYPE_XY_PLOT;
+		} else if (parameter.getClass() == this.classAndMethodContainer.getMeterGaugeClass()) {
+			return DisplayType.TYPE_METER_GAUGE;
 		} 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 cb2b991c..5ea90eaf 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,6 +16,7 @@
 
 package kieker.webgui.web.beans.view;
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
@@ -42,6 +43,7 @@ import kieker.webgui.web.beans.application.ProjectsBean;
 import kieker.webgui.web.utility.CockpitLayout;
 
 import org.primefaces.component.chart.line.LineChart;
+import org.primefaces.component.chart.metergauge.MeterGaugeChart;
 import org.primefaces.component.dashboard.Dashboard;
 import org.primefaces.component.panel.Panel;
 import org.primefaces.model.DashboardColumn;
@@ -50,6 +52,7 @@ import org.primefaces.model.DefaultDashboardColumn;
 import org.primefaces.model.DefaultDashboardModel;
 import org.primefaces.model.chart.CartesianChartModel;
 import org.primefaces.model.chart.LineChartSeries;
+import org.primefaces.model.chart.MeterGaugeChartModel;
 
 import net.vidageek.mirror.dsl.Mirror;
 import net.vidageek.mirror.exception.MirrorException;
@@ -272,6 +275,9 @@ public class CurrentCockpitBean {
 						case TYPE_XY_PLOT:
 							this.updateXYPlotDisplay(component, displayConnector.getName());
 							break;
+						case TYPE_METER_GAUGE:
+							this.updateMeterGaugeDisplay(component, displayConnector.getName());
+							break;
 						default:
 							// Unknown type
 							this.updateDisplayWithDefaultContent(component);
@@ -427,6 +433,63 @@ public class CurrentCockpitBean {
 		}
 	}
 
+	@SuppressWarnings("unchecked")
+	private void updateMeterGaugeDisplay(final UIComponent component, final String displayConnectorName) {
+		final boolean isAlreadyCorrectlyInitialized = (component.getChildCount() == 1) && (component.getChildren().get(0) instanceof MeterGaugeChart);
+
+		final MeterGaugeChartModel meterGaugeChartModel;
+
+		// Avoid unnecessary component creation. Use the existing components if they are already existing and from the correct type.
+		if (isAlreadyCorrectlyInitialized) {
+			final MeterGaugeChart meterGaugeChart = (MeterGaugeChart) component.getChildren().get(0);
+			meterGaugeChartModel = meterGaugeChart.getValue();
+		} else {
+			final FacesContext facesContext = FacesContext.getCurrentInstance();
+			final Application application = facesContext.getApplication();
+
+			// Create the Primefaces chart component
+			final MeterGaugeChart meterGaugeChart = (MeterGaugeChart) application.createComponent(facesContext, "org.primefaces.component.chart.MeterGaugeChart",
+					"org.primefaces.component.chart.MeterGaugeChartRenderer");
+			meterGaugeChart.setTitle(displayConnectorName);
+
+			// Add the corresponding model
+			meterGaugeChartModel = new MeterGaugeChartModel();
+			meterGaugeChart.setValue(meterGaugeChartModel);
+
+			component.getChildren().clear();
+			component.getChildren().add(meterGaugeChart);
+		}
+
+		try {
+			final Object displayObj = this.projectService.getDisplay(this.projectName, this.activeView.getName(), displayConnectorName);
+
+			final List<Number> intervals = (List<Number>) new Mirror().on(displayObj).invoke().method("getIntervals").withoutArgs();
+			final Number value = (Number) new Mirror().on(displayObj).invoke().method("getValue").withoutArgs();
+
+			if (intervals.isEmpty()) {
+				meterGaugeChartModel.setIntervals(Arrays.asList((Number) 50, 100));
+				meterGaugeChartModel.setValue(0);
+			} else {
+				meterGaugeChartModel.setIntervals(intervals);
+				final Number maxInterval = intervals.get(intervals.size() - 1);
+				if (value.doubleValue() <= maxInterval.doubleValue()) {
+					meterGaugeChartModel.setValue(value);
+				} else {
+					meterGaugeChartModel.setValue(maxInterval);
+				}
+			}
+		} catch (final DisplayNotFoundException ex) {
+			CurrentCockpitBean.LOG.warn("Display not found.", ex);
+			this.updateDisplayWithDefaultContent(component);
+		} catch (final MirrorException ex) {
+			CurrentCockpitBean.LOG.warn("Reflection exception.", ex);
+			this.updateDisplayWithDefaultContent(component);
+		} catch (final InvalidAnalysisStateException ex) {
+			CurrentCockpitBean.LOG.info("Project is in invalid state.", ex);
+			this.updateDisplayWithDefaultContent(component);
+		}
+	}
+
 	@SuppressWarnings("unchecked")
 	private void updateXYPlotDisplay(final UIComponent component, final String displayConnectorName) {
 		final boolean isAlreadyCorrectlyInitialized = (component.getChildCount() == 1) && (component.getChildren().get(0) instanceof LineChart);
diff --git a/Kieker.WebGUI/src/main/webapp/pages/ControllerPage.xhtml b/Kieker.WebGUI/src/main/webapp/pages/ControllerPage.xhtml
index 2561ee44..f2a20143 100644
--- a/Kieker.WebGUI/src/main/webapp/pages/ControllerPage.xhtml
+++ b/Kieker.WebGUI/src/main/webapp/pages/ControllerPage.xhtml
@@ -52,7 +52,7 @@
                         </h:form>
                     </p:panel>
 
-                    <p:panel style="width: 100%; height:100%" header="#{localizedControllerPageMessages.analysisControllerLog}" collapsed="true">
+                    <p:panel style="width: 100%; height:100%" header="#{localizedControllerPageMessages.analysisControllerLog}">
                         <h:form id="analysisControllerLog" style="width: 100%">
                             <p:dataList value="#{currentControllerBean.analysisLog}" var="logEntry">
                                 #{logEntry}
diff --git a/Kieker.WebGUI/src/test/java/kieker/webgui/persistence/impl/utility/Class2ModelInstanceConverterTest.java b/Kieker.WebGUI/src/test/java/kieker/webgui/persistence/impl/utility/Class2ModelInstanceConverterTest.java
index 3e3cb8cb..7f4ff0b8 100644
--- a/Kieker.WebGUI/src/test/java/kieker/webgui/persistence/impl/utility/Class2ModelInstanceConverterTest.java
+++ b/Kieker.WebGUI/src/test/java/kieker/webgui/persistence/impl/utility/Class2ModelInstanceConverterTest.java
@@ -124,7 +124,7 @@ public class Class2ModelInstanceConverterTest {
 		final MIFilter filter = converter.convertFilterClass2ModelInstance(countingFilterCLass, classAndMethodContainer);
 
 		Assert.assertEquals("Properties are not loaded correctly", countingFilterCLass.getCanonicalName(), filter.getClassname());
-		Assert.assertEquals("Properties are not loaded correctly", 3, filter.getDisplays().size());
+		Assert.assertEquals("Properties are not loaded correctly", 4, filter.getDisplays().size());
 		Assert.assertTrue("Properties are not loaded correctly", filter.getRepositories().isEmpty());
 		Assert.assertEquals("Properties are not loaded correctly", 2, filter.getOutputPorts().size());
 		Assert.assertEquals("Properties are not loaded correctly", 1, filter.getInputPorts().size());
-- 
GitLab