Added more generic metric aggregation enum (min, max, avg, stdev).

Change-Id: Iae56a98a765a61d9c3d7cefb13a22dd2bd74eee0
Signed-off-by: Raphael Weber <raphael.weber@vector.com>
diff --git a/plugins/org.eclipse.app4mc.atdb.import.btf/src/org/eclipse/app4mc/atdb/_import/btf/ATDBMetricCalculator.java b/plugins/org.eclipse.app4mc.atdb.import.btf/src/org/eclipse/app4mc/atdb/_import/btf/ATDBMetricCalculator.java
index 1988aea..b877fa6 100644
--- a/plugins/org.eclipse.app4mc.atdb.import.btf/src/org/eclipse/app4mc/atdb/_import/btf/ATDBMetricCalculator.java
+++ b/plugins/org.eclipse.app4mc.atdb.import.btf/src/org/eclipse/app4mc/atdb/_import/btf/ATDBMetricCalculator.java
@@ -18,13 +18,13 @@
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
 
 import org.eclipse.app4mc.atdb.ATDBConnection;
+import org.eclipse.app4mc.atdb.MetricAggregation;
 import org.eclipse.app4mc.atdb._import.btf.model.BTFCombiState;
 import org.eclipse.app4mc.atdb._import.btf.model.BTFCountMetric;
 import org.eclipse.app4mc.atdb._import.btf.model.BTFEntityState;
@@ -137,23 +137,18 @@
 			}
 	
 			// calculate entity metrics min max avg for all time metric values
-			final List<String> mma = Arrays.asList("Min", "Max", "Avg", "StDev");
 			for (final String entityInstanceTimeMetric : entityInstanceTimeMetrics) {
-				for (final String kind : mma) {
+				for (final MetricAggregation kind : MetricAggregation.values()) {
 					metricStmt.setString(1, entityInstanceTimeMetric + "_" + kind);
 					metricStmt.setString(2, "time");
 					metricStmt.addBatch();
 				}
 			}
-			for (final String kind : mma) {
-				String aggregateFunction = kind.toUpperCase() + "(CAST(value AS INTEGER))";
-				if (kind.equalsIgnoreCase("AVG") || kind.equalsIgnoreCase("STDEV")) {
-					aggregateFunction = "printf('%.2f'," + aggregateFunction + ")";
-				}
+			for (final MetricAggregation kind : MetricAggregation.values()) {
 				statement.addBatch("INSERT INTO entityMetricValue SELECT "//
 						+ "  entityId,"//
 						+ "  (SELECT id FROM metric WHERE name = (SELECT name FROM metric WHERE id = metricId) || '_" + kind + "'),"//
-						+ "  " + aggregateFunction + " FROM entityInstanceMetricValue WHERE "//
+						+ "  " + kind.getSQLStr("value") + " FROM entityInstanceMetricValue WHERE "//
 						+ "metricId IN (SELECT id FROM metric WHERE dimension = 'time') GROUP BY entityId, metricId;");
 			}
 	
diff --git a/plugins/org.eclipse.app4mc.atdb.metrics/src/org/eclipse/app4mc/atdb/metrics/DatabaseAccess.java b/plugins/org.eclipse.app4mc.atdb.metrics/src/org/eclipse/app4mc/atdb/metrics/DatabaseAccess.java
index b4689a3..96c6dc6 100644
--- a/plugins/org.eclipse.app4mc.atdb.metrics/src/org/eclipse/app4mc/atdb/metrics/DatabaseAccess.java
+++ b/plugins/org.eclipse.app4mc.atdb.metrics/src/org/eclipse/app4mc/atdb/metrics/DatabaseAccess.java
@@ -21,8 +21,10 @@
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import org.eclipse.app4mc.atdb.ATDBConnection;
+import org.eclipse.app4mc.atdb.MetricAggregation;
 import org.eclipse.core.resources.IFile;
 
 public class DatabaseAccess implements AutoCloseable {
@@ -118,14 +120,13 @@
 				+ "  entitiesToConsider(id) AS (SELECT id FROM entity" + entityTypesFilter + "),\n"
 				+ "  metricsToConsider(id) AS (SELECT id FROM metric" + metricDimensionsFilter + "),\n"
 				+ "  precalculated(" + getPrependedColumnsEntityIdStr(prependColumns)
-					+ entityTypeLabel.toLowerCase() + "Id, metricId, minimum, average, maximum, stanDev) AS (SELECT\n"
+					+ entityTypeLabel.toLowerCase() + "Id, metricId, " + Stream.of(MetricAggregation.values())
+							.map(ma -> ma.getSQLLabel()).collect(Collectors.joining(", ")) + ") AS (SELECT\n"
 				+ getPrependedColumnsEntityId2Query(prependColumns, "    ")
 				+ "    entityInstanceMetricValue.entityId,\n"
 				+ "    entityInstanceMetricValue.metricId,\n"
-				+ "    MIN(CAST(entityInstanceMetricValue.value AS INTEGER)),\n"
-				+ "    printf('%.2f', AVG(CAST(entityInstanceMetricValue.value AS INTEGER))),\n"
-				+ "    MAX(CAST(entityInstanceMetricValue.value AS INTEGER)),\n"
-				+ "    printf('%.2f', STDEV(CAST(entityInstanceMetricValue.value AS INTEGER)))\n"
+				+ Stream.of(MetricAggregation.values()).map(ma -> "    " + ma.getSQLStr("entityInstanceMetricValue.value"))
+						.collect(Collectors.joining(",\n")) + "\n"
 				+ "  FROM entityInstanceMetricValue\n"
 				+ "  WHERE entityId IN (SELECT id FROM entitiesToConsider) AND\n"
 				+ "    metricId IN (SELECT id FROM metricsToConsider)\n"
@@ -135,10 +136,8 @@
 				+ "  (SELECT name FROM entity WHERE id = " + entityTypeLabel.toLowerCase() + "Id) AS '" + entityTypeLabel + " "
 					+ Messages.DBViewer_nameTitle + "',\n"
 				+ "  (SELECT name FROM metric WHERE id = metricId) AS '" + Messages.DBViewer_metricColumnTitle + "',\n"
-				+ "  minimum AS '" + String.format(Messages.DBViewer_minimumColumnTitle, timeBase) + "',\n"
-				+ "  average AS '" + String.format(Messages.DBViewer_averageColumnTitle, timeBase) + "',\n"
-				+ "  maximum AS '" + String.format(Messages.DBViewer_maximumColumnTitle, timeBase) + "',\n"
-				+ "  stanDev AS '" + String.format(Messages.DBViewer_stanDevColumnTitle, timeBase) + "'\n"
+				+ Stream.of(MetricAggregation.values()).map(ma -> "  " + ma.getSQLLabel() + " AS '" + ma.getUILabel() + " [" + timeBase + "]'")
+						.collect(Collectors.joining(",\n")) + "\n"
 				+ "FROM precalculated\n"
 				+ "ORDER BY " + getPrependedColumns2Order(prependColumns) + entityTypeLabel.toLowerCase() + "Id, metricId;"; //$NON-NLS-1$
 		if (!this.query2Result.containsKey(queryString)) {
diff --git a/plugins/org.eclipse.app4mc.atdb/META-INF/MANIFEST.MF b/plugins/org.eclipse.app4mc.atdb/META-INF/MANIFEST.MF
index ba51c69..80be9e4 100644
--- a/plugins/org.eclipse.app4mc.atdb/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.app4mc.atdb/META-INF/MANIFEST.MF
@@ -3,7 +3,8 @@
 Bundle-Name: AMALTHEA Trace DataBase access
 Bundle-SymbolicName: org.eclipse.app4mc.atdb;singleton:=true
 Bundle-Version: 1.0.0.qualifier
-Require-Bundle: org.sqlite.jdbc;visibility:=reexport
+Require-Bundle: org.sqlite.jdbc;visibility:=reexport,
+ org.eclipse.osgi
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Bundle-ActivationPolicy: lazy
 Bundle-Vendor: Eclipse APP4MC
diff --git a/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/ATDBBuilder.java b/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/ATDBBuilder.java
index 03c48c1..922f4a6 100644
--- a/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/ATDBBuilder.java
+++ b/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/ATDBBuilder.java
@@ -169,12 +169,12 @@
 		// human readable event chain table (extract from entity)
 		this.connection.executeUpdate("CREATE VIEW IF NOT EXISTS vEventChainEntity AS SELECT\n"
 				+ "  name AS eventChainName,\n"
-				+ "  (SELECT GROUP_CONCAT(name, ', ') FROM event WHERE id IN (SELECT value FROM propertyValue WHERE"
-				+ "    entityId = ecEntity.id AND propertyId = (SELECT id FROM property WHERE name = 'ecStimulus'))) AS stimulus,\n"
-				+ "  (SELECT GROUP_CONCAT(name, ', ') FROM event WHERE id IN (SELECT value FROM propertyValue WHERE"
-				+ "    entityId = ecEntity.id AND propertyId = (SELECT id FROM property WHERE name = 'ecResponse'))) AS response,\n"
-				+ "  (SELECT GROUP_CONCAT(name, ', ') FROM entity          WHERE id IN (SELECT value FROM propertyValue WHERE"
-				+ "    entityId = ecEntity.id AND propertyId = (SELECT id FROM property WHERE name = 'ecItems'   ))) AS items,\n"
+				+ "  (SELECT GROUP_CONCAT((SELECT name FROM event  WHERE id = value), ', ') FROM propertyValue WHERE\n"
+				+ "    entityId = ecEntity.id AND propertyId = (SELECT id FROM property WHERE name = 'ecStimulus')) AS stimulus,\n"
+				+ "  (SELECT GROUP_CONCAT((SELECT name FROM event  WHERE id = value), ', ') FROM propertyValue WHERE\n"
+				+ "    entityId = ecEntity.id AND propertyId = (SELECT id FROM property WHERE name = 'ecResponse')) AS response,\n"
+				+ "  (SELECT GROUP_CONCAT((SELECT name FROM entity WHERE id = value), ', ') FROM propertyValue WHERE\n"
+				+ "    entityId = ecEntity.id AND propertyId = (SELECT id FROM property WHERE name = 'ecItems')) AS items,\n"
 				+ "  (SELECT value FROM propertyValue WHERE entityId = ecEntity.id AND propertyId ="
 				+ "    (SELECT id FROM property WHERE name = 'ecMinItemsCompleted')) AS minItemsCompleted,\n"
 				+ "  EXISTS(SELECT value FROM propertyValue WHERE entityId = ecEntity.id AND propertyId ="
diff --git a/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/ATDBConnection.java b/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/ATDBConnection.java
index 25a48af..2659f5c 100644
--- a/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/ATDBConnection.java
+++ b/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/ATDBConnection.java
@@ -112,11 +112,16 @@
 		}
 	}
 	
-	public void executeBatchStatementAndConsumeGeneratedIDs(final Statement statement,
-			final ThrowingConsumer<ResultSet, SQLException> consumer) throws SQLException {
-		executeBatchStatements(statement);
-		final ResultSet generatedKeys = statement.getGeneratedKeys();
-		consumer.accept(generatedKeys);
+	public boolean tableExists(final String...tableName) throws SQLException {
+		try (final PreparedStatement statement = this.connection.prepareStatement("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?;",
+				ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)) {
+			statement.setArray(1, this.connection.createArrayOf("VARCHAR", tableName));
+			final ResultSet resultSet = statement.executeQuery();
+			if (resultSet.next()) {
+				return resultSet.getBoolean(1);
+			}
+		}
+		return false;
 	}
 
 }
diff --git a/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/MetricAggregation.java b/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/MetricAggregation.java
new file mode 100644
index 0000000..142db33
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/MetricAggregation.java
@@ -0,0 +1,36 @@
+package org.eclipse.app4mc.atdb;
+
+public enum MetricAggregation {
+	Min(Strings.MetricAggregation_minimum),
+	Max(Strings.MetricAggregation_maximum),
+	Avg(Strings.MetricAggregation_average, "printf('%.2f', ", ")"),
+	StDev(Strings.MetricAggregation_stanDev, "printf('%.2f', ", ")");
+	
+	private final String sqlStrPrefix;
+	private final String sqlStrSuffix;
+	private final String uiLabel;
+	private final String sqlLabel;
+	
+	private MetricAggregation(final String uiLabel) {
+		this(uiLabel, "", "");
+	}
+	
+	private MetricAggregation(final String uiLabel, final String extraPrefix, final String extraSuffix) {
+		this.uiLabel = uiLabel;
+		this.sqlLabel = uiLabel.replaceAll("\\W", "").toLowerCase();
+		this.sqlStrPrefix = extraPrefix + this.name().toUpperCase() + "(CAST(";
+		this.sqlStrSuffix = " AS INTEGER))" + extraSuffix;
+	}
+	
+	public String getSQLStr(final String valueProvider) {
+		return this.sqlStrPrefix + valueProvider + this.sqlStrSuffix;
+	}
+	
+	public String getUILabel() {
+		return this.uiLabel;
+	}
+	
+	public String getSQLLabel() {
+		return this.sqlLabel;
+	}
+}
diff --git a/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/Strings.java b/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/Strings.java
new file mode 100644
index 0000000..e2943b9
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/Strings.java
@@ -0,0 +1,32 @@
+/**
+ ********************************************************************************
+ * Copyright (c) 2020 Eclipse APP4MC contributors.
+ * 
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ * 
+ * SPDX-License-Identifier: EPL-2.0
+ * 
+ ********************************************************************************
+ */
+
+package org.eclipse.app4mc.atdb;
+
+import org.eclipse.osgi.util.NLS;
+
+public class Strings extends NLS {
+	private static final String BUNDLE_NAME = "org.eclipse.app4mc.atdb.strings"; //$NON-NLS-1$
+	public static String MetricAggregation_minimum;
+	public static String MetricAggregation_maximum;
+	public static String MetricAggregation_average;
+	public static String MetricAggregation_stanDev;
+	static {
+		// initialize resource bundle
+		NLS.initializeMessages(BUNDLE_NAME, Strings.class);
+	}
+
+	private Strings() {
+	}
+
+}
diff --git a/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/strings.properties b/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/strings.properties
new file mode 100644
index 0000000..8965ecf
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.atdb/src/org/eclipse/app4mc/atdb/strings.properties
@@ -0,0 +1,4 @@
+MetricAggregation_minimum=Minimum
+MetricAggregation_maximum=Maximum
+MetricAggregation_average=Average
+MetricAggregation_stanDev=Std. Dev.