diff --git a/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/view/fx/MetricsFXController.java b/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/view/fx/MetricsFXController.java index 7fd2453d1136fb7bd9cfdffe29937de23387c76f..5610d6a806b30151551361b15d23edcef1e2da19 100644 --- a/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/view/fx/MetricsFXController.java +++ b/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/view/fx/MetricsFXController.java @@ -41,6 +41,7 @@ import org.fortiss.tooling.common.ui.javafx.layout.CompositeFXControllerBase; import org.fortiss.tooling.common.ui.javafx.style.FillStyle; import org.fortiss.tooling.common.ui.javafx.style.FontStyle; import org.fortiss.tooling.common.ui.javafx.style.LineStyle; +import org.fortiss.tooling.ext.quality.data.MetricKey; import org.fortiss.tooling.ext.quality.data.MetricTreeNode; import org.fortiss.tooling.ext.quality.service.ModelQualityService; import org.fortiss.tooling.kernel.model.IProjectRootElement; @@ -103,7 +104,6 @@ public class MetricsFXController extends CompositeFXControllerBase<SplitPane, No @Override public void initialize() { // Not used - } /** {@inheritDoc} */ @@ -166,8 +166,8 @@ public class MetricsFXController extends CompositeFXControllerBase<SplitPane, No pieChart.getData().clear(); for(var child : node.getChildren()) { - PieChart.Data slice = - new PieChart.Data(child.getName(), child.getTotalPortAmount()); + PieChart.Data slice = new PieChart.Data(child.getName(), + child.getStoredMetrics().get(MetricKey.NUMBER_OF_TOTAL_PORTS)); pieChart.getData().add(slice); pieChart.setLegendVisible(false); pieChart.setTitle(""); @@ -196,8 +196,8 @@ public class MetricsFXController extends CompositeFXControllerBase<SplitPane, No } /** - * @param provider - * the provider for which the spider chart should be generated + * @param node + * of which the data will be visualized * @return {@link SpiderChartViewer} with the matching metrics */ private static SpiderChartViewer buildSpiderChart(MetricTreeNode node) { @@ -212,8 +212,9 @@ public class MetricsFXController extends CompositeFXControllerBase<SplitPane, No return null; } - double maxval = - children.stream().mapToDouble(p -> p.getTotalPortAmount()).max().getAsDouble(); + double maxval = children.stream() + .mapToDouble(p -> p.getStoredMetrics().get(MetricKey.NUMBER_OF_TOTAL_PORTS)).max() + .getAsDouble(); chartStyle.setUseIndividualAxisSegments(false); chartStyle.setTitleStyle(new FontStyle("Verdana", 14, BLUE.brighter())); @@ -227,7 +228,8 @@ public class MetricsFXController extends CompositeFXControllerBase<SplitPane, No chartStyle.setAxisStyle(testing, aStyle3Segs); spiderChart.addAxis(testing); - elementData.setPoint(testing, child.getTotalPortAmount()); + elementData.setPoint(testing, + child.getStoredMetrics().get(MetricKey.NUMBER_OF_TOTAL_PORTS)); } spiderChart.addData(elementData); diff --git a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/AF3QualityActivator.java b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/AF3QualityActivator.java index ef935dcfcbd73bcfa1662463ac9015bf83e3a528..9debc4bb2adb87ce4bfb8dd5cec203f5b79477ba 100644 --- a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/AF3QualityActivator.java +++ b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/AF3QualityActivator.java @@ -42,7 +42,7 @@ public class AF3QualityActivator extends Plugin { System.out.println("[Plugin] " + PLUGIN_ID + " started."); ModelQualityService.getInstance().startService(); IModelQualityService.getInstance().registerMetricProvider( - new HierarchicElementSizeProvider(), IHierarchicElement.class); + new HierarchicElementProvider(), IHierarchicElement.class); } /** {@inheritDoc} */ diff --git a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/HierarchicElementSizeProvider.java b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/HierarchicElementProvider.java similarity index 70% rename from org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/HierarchicElementSizeProvider.java rename to org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/HierarchicElementProvider.java index cb3eb2cb27bd087682e1d3f7e9b315c770fc7c65..2889efa8dc5e6ea8ec276e4bf5b86d60cfefc0d1 100644 --- a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/HierarchicElementSizeProvider.java +++ b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/HierarchicElementProvider.java @@ -20,7 +20,9 @@ import java.util.Optional; import org.eclipse.emf.common.util.EList; import org.fortiss.tooling.base.model.element.IHierarchicElement; import org.fortiss.tooling.ext.quality.data.MetricDataManager; +import org.fortiss.tooling.ext.quality.data.MetricKey; import org.fortiss.tooling.ext.quality.data.MetricTreeNode; +import org.fortiss.tooling.kernel.model.IIdLabeled; import org.fortiss.tooling.kernel.model.INamedCommentedElement; /** @@ -30,7 +32,7 @@ import org.fortiss.tooling.kernel.model.INamedCommentedElement; * @author blaschke * @author groh */ -public class HierarchicElementSizeProvider implements IModelQualityProvider<IHierarchicElement> { +public class HierarchicElementProvider implements IModelQualityProvider<IHierarchicElement> { /** * returns an array of integers or <String,Double> Map Number of children of the * hierarchical Element (on this level) Number of ports on the hierarchical @@ -39,37 +41,13 @@ public class HierarchicElementSizeProvider implements IModelQualityProvider<IHie * whole tree Average SubTree Size */ - /** Key for the metric counting ports */ - public static final String NUMBER_OF_PORTS = "numberOfPorts"; - - /** Key for the metric counting elements */ - public static final String NUMBER_OF_CONTAINED_ELEMENTS = "numberOfContainedElements"; - - /** Key for the metric counting channels */ - public static final String NUMBER_OF_CHANNELS = "numberOfChannels"; - - /** Key for the metric counting the total amount of ports contained */ - public static final String NUMBER_OF_TOTAL_PORTS = "numberOfTotalPorts"; - /** Key for the metric counting the total amount of elements contained */ - public static final String NUMBER_OF_TOTAL_ELEMENTS = "numberOfTotalElements"; - /** Key for the metric counting the total amount of elements which can be commented */ - public static final String NUMBER_OF_TOTAL_COMMENTABLE_ELEMENTS = - "numberOfTotalCommentableElements"; - /** Key for the metric counting the total amount of elements which are commented */ - public static final String NUMBER_OF_TOTAL_COMMENTED_ELEMENTS = - "numberOfTotalCommentedElements"; - /** - * Key for the metric counting the total amount of elements which do not contain other elements - */ - public static final String NUMBER_OF_TOTAL_LEAF_ELEMENTS = "numberOfTotalLeafElements"; - /** * List containing all HierarchicElementSizeProvider for components inside the * IHierarchicElement */ /** */ - public HierarchicElementSizeProvider() { + public HierarchicElementProvider() { super(); } @@ -80,10 +58,11 @@ public class HierarchicElementSizeProvider implements IModelQualityProvider<IHie var metrics = node.getStoredMetrics(); boolean isElementCommentable = currentElement instanceof INamedCommentedElement; - metrics.put(NUMBER_OF_TOTAL_COMMENTABLE_ELEMENTS, isElementCommentable ? 1.0 : 0.0); + metrics.put(MetricKey.NUMBER_OF_TOTAL_COMMENTABLE_ELEMENTS, + isElementCommentable ? 1.0 : 0.0); String comment = isElementCommentable ? ((INamedCommentedElement)currentElement).getComment() : null; - metrics.put(NUMBER_OF_TOTAL_COMMENTED_ELEMENTS, + metrics.put(MetricKey.NUMBER_OF_TOTAL_COMMENTED_ELEMENTS, comment != null && comment != "" ? 1.0 : 0.0); if(isElementCommentable) { node.setName(((INamedCommentedElement)currentElement).getName()); @@ -134,16 +113,18 @@ public class HierarchicElementSizeProvider implements IModelQualityProvider<IHie // EcoreUtils.pickInstanceOf(target, srcList) var metrics = node.getStoredMetrics(); - metrics.put(NUMBER_OF_PORTS, (double)currentElement.getConnectors().size()); - metrics.put(NUMBER_OF_CONTAINED_ELEMENTS, + metrics.put(MetricKey.UNQIUE_ID, (currentElement instanceof IIdLabeled) + ? ((IIdLabeled)currentElement).getId() : -1.0); + metrics.put(MetricKey.NUMBER_OF_PORTS, (double)currentElement.getConnectors().size()); + metrics.put(MetricKey.NUMBER_OF_CONTAINED_ELEMENTS, (double)currentElement.getContainedElements().size()); - metrics.put(NUMBER_OF_CHANNELS, (double)currentElement.getConnections().size()); + metrics.put(MetricKey.NUMBER_OF_CHANNELS, (double)currentElement.getConnections().size()); // depth metrics - metrics.put(NUMBER_OF_TOTAL_PORTS, (double)currentElement.getConnectors().size()); - metrics.put(NUMBER_OF_TOTAL_ELEMENTS, 1.0); + metrics.put(MetricKey.NUMBER_OF_TOTAL_PORTS, (double)currentElement.getConnectors().size()); + metrics.put(MetricKey.NUMBER_OF_TOTAL_ELEMENTS, 1.0); - metrics.put(NUMBER_OF_TOTAL_LEAF_ELEMENTS, + metrics.put(MetricKey.NUMBER_OF_TOTAL_LEAF_ELEMENTS, currentElement.getContainedElements().size() == 0 ? 1.0 : 0.0); for(IHierarchicElement containedElement : currentElement.getContainedElements()) { @@ -151,9 +132,11 @@ public class HierarchicElementSizeProvider implements IModelQualityProvider<IHie node.getChildren().add(child); apply(manager, child, containedElement); - for(String key : new String[] {NUMBER_OF_TOTAL_PORTS, NUMBER_OF_TOTAL_ELEMENTS, - NUMBER_OF_TOTAL_COMMENTABLE_ELEMENTS, NUMBER_OF_TOTAL_COMMENTED_ELEMENTS, - NUMBER_OF_TOTAL_LEAF_ELEMENTS}) { + for(MetricKey key : new MetricKey[] {MetricKey.NUMBER_OF_TOTAL_PORTS, + MetricKey.NUMBER_OF_TOTAL_ELEMENTS, + MetricKey.NUMBER_OF_TOTAL_COMMENTABLE_ELEMENTS, + MetricKey.NUMBER_OF_TOTAL_COMMENTED_ELEMENTS, + MetricKey.NUMBER_OF_TOTAL_LEAF_ELEMENTS}) { metrics.merge(key, child.getStoredMetrics().get(key), Double::sum); } } diff --git a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/HierarchicalMetricDataContainer.java b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/HierarchicalMetricDataContainer.java index 175f35a94dd0a8977c371c373bde05b2edece6b3..f75a4d67ce1cabc175131e93b039de26be1de190 100644 --- a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/HierarchicalMetricDataContainer.java +++ b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/HierarchicalMetricDataContainer.java @@ -18,10 +18,10 @@ package org.fortiss.tooling.ext.quality.data; import java.util.HashMap; import java.util.Map; -import org.fortiss.tooling.ext.quality.HierarchicElementSizeProvider; +import org.fortiss.tooling.ext.quality.HierarchicElementProvider; /** - * Class for storing data generated by the {@link HierarchicElementSizeProvider} + * Class for storing data generated by the {@link HierarchicElementProvider} * * @author groh */ diff --git a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/MetricKey.java b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/MetricKey.java new file mode 100644 index 0000000000000000000000000000000000000000..2b0e08ff0d16d02eab1d953afa9519ac526ea188 --- /dev/null +++ b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/MetricKey.java @@ -0,0 +1,50 @@ +/*-------------------------------------------------------------------------+ +| Copyright 2023 fortiss GmbH | +| | +| Licensed under the Apache License, Version 2.0 (the "License"); | +| you may not use this file except in compliance with the License. | +| You may obtain a copy of the License at | +| | +| http://www.apache.org/licenses/LICENSE-2.0 | +| | +| Unless required by applicable law or agreed to in writing, software | +| distributed under the License is distributed on an "AS IS" BASIS, | +| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | +| See the License for the specific language governing permissions and | +| limitations under the License. | ++--------------------------------------------------------------------------*/ +package org.fortiss.tooling.ext.quality.data; + +/** + * + * @author groh + */ +public enum MetricKey { + + // + // Metrics provided by the HierarchicElementProvider + // + /** Unique ID of the element */ + UNQIUE_ID, + + /** Key for the metric counting ports */ + NUMBER_OF_PORTS, + /** Key for the metric counting elements */ + NUMBER_OF_CONTAINED_ELEMENTS, + /** Key for the metric counting channels */ + NUMBER_OF_CHANNELS, + + // Metrics which are collected over all children nodes + /** Key for the metric counting the total amount of ports contained */ + NUMBER_OF_TOTAL_PORTS, + /** Key for the metric counting the total amount of elements contained */ + NUMBER_OF_TOTAL_ELEMENTS, + /** Key for the metric counting the total amount of elements which can be commented */ + NUMBER_OF_TOTAL_COMMENTABLE_ELEMENTS, + /** Key for the metric counting the total amount of elements which are commented */ + NUMBER_OF_TOTAL_COMMENTED_ELEMENTS, + /** + * Key for the metric counting the total amount of elements which do not contain other elements + */ + NUMBER_OF_TOTAL_LEAF_ELEMENTS, +} diff --git a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/MetricTreeNode.java b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/MetricTreeNode.java index 200c67bd80970334780fdb23915b43ab98b52b61..96f7044720798fc16eb60912c11a621be4998f3c 100644 --- a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/MetricTreeNode.java +++ b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/MetricTreeNode.java @@ -19,6 +19,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import org.fortiss.tooling.ext.quality.IModelQualityProvider; @@ -47,7 +48,7 @@ public class MetricTreeNode { private Map<Class<? extends IModelQualityProvider<?>>, IMetricDataContainer> dataContainers; /** Map containing all metrics which are a double */ - private Map<String, Double> storedMetrics = new HashMap<>(); + private Map<MetricKey, Double> storedMetrics; /** name of the element which is associated with this data */ private String name; @@ -56,8 +57,9 @@ public class MetricTreeNode { * Constructs a new node */ public MetricTreeNode() { - children = new ArrayList<MetricTreeNode>(); + children = new ArrayList<>(); dataContainers = new HashMap<>(); + storedMetrics = new HashMap<>(); } /** @@ -92,11 +94,24 @@ public class MetricTreeNode { /** * @return the stored metrics map */ - public Map<String, Double> getStoredMetrics() { + public Map<MetricKey, Double> getStoredMetrics() { return storedMetrics; } - public double getTotalPortAmount() { - return storedMetrics.get("numberOfTotalPorts"); + /** + * Traverses the tree in post-order + * + * @param consumer + * which is applied to each node + */ + public void traverseTree(Consumer<MetricTreeNode> consumer) { + + // traverse all children + for(var child : getChildren()) { + child.traverseTree(consumer); + } + + // apply consumer to self + consumer.accept(this); } } diff --git a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/service/ModelQualityService.java b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/service/ModelQualityService.java index 82c09021b163cd13ecb6f78aec99d7c5a086edc3..ee7b9188b966fb21928668f467cb5bed7ddaee6a 100644 --- a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/service/ModelQualityService.java +++ b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/service/ModelQualityService.java @@ -26,22 +26,23 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; -import java.util.Date; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import org.fortiss.tooling.base.model.element.IHierarchicElement; -import org.fortiss.tooling.ext.quality.HierarchicElementSizeProvider; +import org.fortiss.tooling.ext.quality.HierarchicElementProvider; import org.fortiss.tooling.ext.quality.IModelQualityProvider; import org.fortiss.tooling.ext.quality.data.MetricDataManager; +import org.fortiss.tooling.ext.quality.data.MetricKey; import org.fortiss.tooling.ext.quality.data.MetricTreeNode; import org.fortiss.tooling.kernel.extension.data.ITopLevelElement; import org.fortiss.tooling.kernel.introspection.IIntrospectionDetailsItem; @@ -138,14 +139,13 @@ public class ModelQualityService extends EObjectAwareServiceBase<IModelQualityPr // Get first element, there should not be any other elements IHierarchicElement firstNode = elements.get(0); MetricTreeNode root_node = new MetricTreeNode(); - HierarchicElementSizeProvider hes = new HierarchicElementSizeProvider(); + HierarchicElementProvider hes = new HierarchicElementProvider(); hes.apply(metricDataManagerInstance, root_node, firstNode); root_nodes.put(rootElement, root_node); } } - // result.forEach((k, v) -> last_metrics.merge(k, v, (oldValue, newValue) -> newValue)); - // metricExtractionToCSV(result); - // return result; + // Store all currently saved metrics to the csv + metricExtractionToCSV(metricDataManagerInstance.getRootNodes()); } /** */ @@ -193,20 +193,19 @@ public class ModelQualityService extends EObjectAwareServiceBase<IModelQualityPr /** * Method to write the data into a csv * - * @param data + * @param map * to convert into csv * */ - public void metricExtractionToCSV( - Map<IProjectRootElement, IModelQualityProvider<? extends EObject>> data) { + public void metricExtractionToCSV(Map<IProjectRootElement, MetricTreeNode> map) { // check if there is any data to export - if(data == null || data.isEmpty()) { + if(map == null || map.isEmpty()) { return; } // path to csv file - Path path = Paths.get("data_ultra_cool.csv"); + Path path = Paths.get("data_mega_cool.csv"); List<String> allKeys = new ArrayList<>(); boolean createNewIndex = true; @@ -228,14 +227,14 @@ public class ModelQualityService extends EObjectAwareServiceBase<IModelQualityPr if(createNewIndex) { // Create new index and write it into the first line of the file - var anyProvider = data.values().iterator().next(); - // List<String> keys = anyProvider.metricKeys(); - List<String> keys = new ArrayList<String>(); allKeys.add("timestamp"); - allKeys.add("root"); - allKeys.add("node"); - allKeys.add("parent"); - allKeys.addAll(keys); + allKeys.add("root_name"); + allKeys.add("name"); + allKeys.add("children"); + // Collect all MetricKeys, convert them to a string and append them to the allKeys + // list + allKeys.addAll(Arrays.stream(MetricKey.values()).map(MetricKey::toString) + .map(String::toLowerCase).collect(Collectors.toList())); // Write first line writer.write(String.join(",", allKeys)); @@ -248,87 +247,37 @@ public class ModelQualityService extends EObjectAwareServiceBase<IModelQualityPr DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME; String formattedDateTime = dateTime.format(formatter); - data.forEach((rootProject, rootProvider) -> { + map.forEach((rootProject, rootNode) -> { // iterate over all project roots String rootName = rootProject.getName(); - // rootProvider.traverse(new IVisitorModelQualityProvider() { - // - // @Override - // public void accept(HierarchicElementSizeProvider provider) { - // - // var metrics = provider.getStoredMetrics(); - // // These 4 data entries are just concatenated in front - // var startStream = Stream.of(formattedDateTime, rootName, "null", "null"); - // // Collect all values from provider in the correct order and combine - // var values = Stream - // .concat(startStream, - // valueKeys.stream().map(metrics::get).map(String::valueOf)) - // .collect(Collectors.joining(",")); - // - // try { - // // write values - // writer.write(values); - // writer.write("\n"); - // } catch(IOException e) { - // e.printStackTrace(); - // } - // } - // }); + rootNode.traverseTree(node -> { + var metrics = node.getStoredMetrics(); + // collect IDs of children + String children_ids = node.getChildren().stream() + .map(n -> n.getStoredMetrics().get(MetricKey.UNQIUE_ID)) + .map(id -> id.toString()).reduce((a, b) -> a + " " + b).orElse(""); + + // These 4 data entries are just concatenated in front + var startStream = + Stream.of(formattedDateTime, rootName, node.getName(), children_ids); + // Collect all values from provider in the correct order and combine + var values = Stream + .concat(startStream, valueKeys.stream().map(String::toUpperCase) + .map(MetricKey::valueOf).map(metrics::get).map(String::valueOf)) + .collect(Collectors.joining(",")); + + try { + // write values + writer.write(values); + writer.write("\n"); + } catch(IOException e) { + e.printStackTrace(); + } + }); }); } catch(IOException e) { e.printStackTrace(); } } - - /** - * - * @author blaschke - */ - public static class MetricCSVWriter { - /** */ - private static final String FILE_PATH = "data_ultra_cool.csv"; - /** */ - private BufferedWriter writer; - - /** - * @throws IOException - */ - public void openFile() throws IOException { - writer = new BufferedWriter(new FileWriter(FILE_PATH, true)); - } - - /** - * @param data - */ - public void writeData(Map<String, Double> data) { - try { - String timestamp = getCurrentTimestamp(); - writer.write(timestamp + ": "); - for(Map.Entry<String, Double> entry : data.entrySet()) { - writer.write(entry.getKey() + ":" + entry.getValue() + ","); - writer.newLine(); - } - writer.flush(); - } catch(IOException e) { - e.printStackTrace(); - } - } - - /** - * @throws IOException - */ - public void closeFile() throws IOException { - if(writer != null) { - writer.close(); - } - } - - /** */ - private String getCurrentTimestamp() { - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - Date now = new Date(); - return dateFormat.format(now); - } - } }