From 402e981e73ba3063bbec74cb884e0e9e6e3c9ec3 Mon Sep 17 00:00:00 2001
From: Eddie Groh <groh@fortiss.org>
Date: Mon, 19 Jun 2023 17:43:00 +0200
Subject: [PATCH] Refactored HierarchicElementSizeProvider Issue-Ref: 4310
 Issue-Url: https://git.fortiss.org/af3/af3/-/issues/4310 Signed-off-by: Eddie
 Groh <groh@fortiss.org>

---
 .../META-INF/MANIFEST.MF                      |   2 +
 .../build.properties                          |   7 +-
 .../HierarchicElementSizeProvider.java        | 430 ++++++------------
 .../quality/service/ModelQualityService.java  |  16 +-
 4 files changed, 151 insertions(+), 304 deletions(-)

diff --git a/org.fortiss.tooling.ext.quality.ui/META-INF/MANIFEST.MF b/org.fortiss.tooling.ext.quality.ui/META-INF/MANIFEST.MF
index 7fcef617d..6aae7a77c 100644
--- a/org.fortiss.tooling.ext.quality.ui/META-INF/MANIFEST.MF
+++ b/org.fortiss.tooling.ext.quality.ui/META-INF/MANIFEST.MF
@@ -5,6 +5,8 @@ Bundle-SymbolicName: org.fortiss.tooling.ext.quality.ui;singleton:=true
 Bundle-Version: 1.0.0
 Automatic-Module-Name: org.fortiss.tooling.ext.quality.ui
 Bundle-RequiredExecutionEnvironment: JavaSE-11
+Bundle-Vendor: %providerName
+Bundle-Activator: org.fortiss.tooling.ext.quality.AF3QualityActivator
 Require-Bundle: org.eclipse.ui.ide;visibility:=reexport,
  org.fortiss.tooling.base.ui;visibility:=reexport,
  org.fortiss.tooling.kernel,
diff --git a/org.fortiss.tooling.ext.quality/build.properties b/org.fortiss.tooling.ext.quality/build.properties
index 6daa0b7a1..25fdb6e84 100644
--- a/org.fortiss.tooling.ext.quality/build.properties
+++ b/org.fortiss.tooling.ext.quality/build.properties
@@ -2,10 +2,7 @@
 
 
 source.. = src/,\
-           generated-src/
-output.. = build/
+           test-src/
 bin.includes = .,\
-               model/,\
                META-INF/,\
-               plugin.xml,\
-               plugin.properties
+               plugin.xml
diff --git a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/service/HierarchicElementSizeProvider.java b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/service/HierarchicElementSizeProvider.java
index 350d038e8..f0a2fbbc7 100644
--- a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/service/HierarchicElementSizeProvider.java
+++ b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/service/HierarchicElementSizeProvider.java
@@ -15,12 +15,20 @@
 +--------------------------------------------------------------------------*/
 package org.fortiss.tooling.ext.quality.service;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.eclipse.emf.common.util.EList;
+import org.fortiss.tooling.base.model.base.HierarchicElementBase;
+import org.fortiss.tooling.base.model.element.IConnector;
 import org.fortiss.tooling.base.model.element.IHierarchicElement;
+import org.fortiss.tooling.base.model.element.IModelElementSpecification;
+import org.fortiss.tooling.kernel.model.INamedCommentedElement;
+import org.fortiss.tooling.kernel.model.INamedElement;
 
 /**
  * {@link IModelQualityProvider} to count the ratio of filled out comments of
@@ -30,315 +38,147 @@ import org.fortiss.tooling.base.model.element.IHierarchicElement;
  */
 public class HierarchicElementSizeProvider 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 Element (on this level)
-	 * Number of channels in the hierarchical element (on this level)
-	 * Number of totalPorts in whole tree
-	 * Number of totalElements in whole tree
-	 * Average SubTree Size
+	 * 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
+	 * Element (on this level) Number of channels in the hierarchical element (on
+	 * this level) Number of totalPorts in whole tree Number of totalElements in
+	 * whole tree Average SubTree Size
 	 */
-	/* */
-	private final String rootName;
-	/**  */
-	Map<String, Double> sizes = new HashMap<String, Double>();
 
-	/** */
-	public HierarchicElementSizeProvider(String rootName) {
-		super();
-		this.rootName = rootName;
-		// TODO Auto-generated constructor stub
-	}
-
-	/** */
-	public String getName() {
-		return this.rootName;
-	}
-
-	/** {@inheritDoc} */
-	@Override
-	public void apply(IHierarchicElement ele) {
-		Map<String, Double> sizes = new HashMap<String, Double>();
-		sizes.put("numberOfPorts", (double)ele.getConnectors().size());
-		sizes.put("numberOfChildren", (double)ele.getContainedElements().size());
-		sizes.put("numberOfChannels", (double)ele.getConnections().size());
-
-		// depth metrics
-		Set<ICounter> depthMetrics = new HashSet<HierarchicElementSizeProvider.ICounter>();
-		PortCounter pc = new PortCounter();
-		ElementCounter ec = new ElementCounter();
-		depthMetrics.add(new PortCounter());
-		depthMetrics.add(new ElementCounter());
-		// traverse whole tree
-		traverse(ele, depthMetrics);
-
-		// put in entries for subtrees
-		sizes.put("numberOfTotalPorts:", (double)pc.getCounter());
-		sizes.put("numberOfTotalElements:", (double)ec.getCounter());
+	public static final String NUMBER_OF_PORTS = "numberOfPorts";
+	public static final String NUMBER_OF_CONTAINED_ELEMENTS = "numberOfContainedElements";
+	public static final String NUMBER_OF_CHANNELS = "numberOfChannels";
 
-		for(IHierarchicElement child : ele.getContainedElements()) {
-			apply(child);
-		}
-		this.sizes = sizes;
-	}
+	public static final String NUMBER_OF_TOTAL_PORTS = "numberOfTotalPorts";
+	public static final String NUMBER_OF_TOTAL_ELEMENTS = "numberOfTotalElements";
+	public static final String NUMBER_OF_TOTAL_COMMENTABLE_ELEMENTS = "numberOfTotalCommentableElements";
+	public static final String NUMBER_OF_TOTAL_COMMENTED_ELEMENTS = "numberOfTotalCommentedElements";
 
+	/** Map containing all metrics concerning the current IHierarchicElement */
+	private Map<String, Double> storedMetrics;
 	/**
-	 * @param currentElement
-	 * @param consumers
+	 * List containing all HierarchicElementSizeProvider for components inside the
+	 * IHierarchicElement
 	 */
-	public void traverse(IHierarchicElement currentElement, Set<ICounter> consumers) {
-		consumers.forEach(c -> c.apply(currentElement));
-		for(IHierarchicElement child : currentElement.getContainedElements()) {
-			traverse(child, consumers);
-		}
-	}
+	private List<HierarchicElementSizeProvider> containedProviders;
 
-	/** */
-	public interface ICounter {
-		/**
-		 * @param ele
-		 */
-		public void apply(IHierarchicElement ele);
-
-		/** */
-		public int getCounter();
+	public Map<String, Double> getStoredMetrics() {
+		return storedMetrics;
 	}
 
 	/** */
-	private class PortCounter implements ICounter {
-		/** Returns port number. */
-		int counter = 0;
-
-		/** {@inheritDoc} */
-		@Override
-		public int getCounter() {
-			return counter;
-		}
-
-		/** */
-		@Override
-		public void apply(IHierarchicElement element) {
-			counter = getCounter() + element.getConnectors().size();
-		}
+	public HierarchicElementSizeProvider() {
+		super();
+		this.storedMetrics = new HashMap<>();
+		this.containedProviders = new ArrayList<>();
 	}
 
-	/** */
-	private class ElementCounter implements ICounter {
-		/** Returns port number. */
-		int counter = 0;
+	/** {@inheritDoc} */
+	@Override
+	public void apply(IHierarchicElement currentElement) {
 
-		/** {@inheritDoc} */
-		@Override
-		public int getCounter() {
-			return counter;
-		}
+		storedMetrics.put(NUMBER_OF_PORTS, (double) currentElement.getConnectors().size());
+		storedMetrics.put(NUMBER_OF_CONTAINED_ELEMENTS, (double) currentElement.getContainedElements().size());
+		storedMetrics.put(NUMBER_OF_CHANNELS, (double) currentElement.getConnections().size());
 
-		/** */
-		@Override
-		public void apply(IHierarchicElement element) {
-			counter += 1;
+		// depth metrics
+		storedMetrics.put(NUMBER_OF_TOTAL_PORTS, (double) currentElement.getConnectors().size());
+		storedMetrics.put(NUMBER_OF_TOTAL_ELEMENTS, 1.0);
+
+		boolean isElementCommentable = currentElement instanceof INamedCommentedElement;
+		storedMetrics.put(NUMBER_OF_TOTAL_COMMENTABLE_ELEMENTS, isElementCommentable ? 1.0 : 0.0);
+		String comment = isElementCommentable ? ((INamedCommentedElement) currentElement).getComment() : null;
+		storedMetrics.put(NUMBER_OF_TOTAL_COMMENTED_ELEMENTS, comment != null && comment != "" ? 1.0 : 0.0);
+
+		for (IHierarchicElement containedElement : currentElement.getContainedElements()) {
+			HierarchicElementSizeProvider provider = new HierarchicElementSizeProvider();
+			containedProviders.add(provider);
+			provider.apply(containedElement);
+
+			for (String key : new String[] { NUMBER_OF_TOTAL_PORTS, NUMBER_OF_TOTAL_ELEMENTS,
+					NUMBER_OF_TOTAL_COMMENTABLE_ELEMENTS, NUMBER_OF_TOTAL_COMMENTED_ELEMENTS }) {
+				storedMetrics.merge(key, provider.storedMetrics.get(key), Double::sum);
+			}
 		}
+//		System.out.println("Finished traversing Node: "
+//				+ ((currentElement instanceof INamedElement) ? ((INamedElement) currentElement).getName()
+//						: "Not Named"));
 	}
-}
 
-/*
- * public abstract class MultiMethodDemo implements IElementConsumer {
- * 
- * @Override
- * public void apply(IHierarchicElement element) {
- * if(element instanceof INamedCommentedElement) {
- * consume((INamedCommentedElement)element);
- * } else {
- * consume(element);
- * }
- * }
- * 
- * public abstract void consume(IHierarchicElement element);
- * 
- * public abstract void consume(INamedCommentedElement element);
- * 
- * }
- */
-
-// public class CloneDetection implements IElementConsumer {
-//
-// private Map<Integer, List<IHierarchicElement>> map = new HashMap<>();
-//
-// @Override
-// public void printResult() {
-// System.out.println("Stuff");
-// }
-//
-// @Override
-// public void apply(IHierarchicElement element) {
-// int hash = 1;
-// for(IConnector connector : element.getConnectors()) {
-// EList<IModelElementSpecification> specifications = connector.getSpecifications();
-// //if(!specifications.isEmpty() &&
-// // connector.getSpecifications().get(0) instanceof PortSpecification) {
-//
-// // PortSpecification port =
-// // (PortSpecification)connector.getSpecifications().get(0);
-// // hash = 31 * hash + (connector instanceof InputPort ? 1 : 2) *
-// // port.getType().getClass().hashCode();
-// } else {
-// // Clone Detection for State diagrams not supported
-// return;
-// }
-// }map.putIfAbsent(hash,new ArrayList<>());
-//
-// List<IHierarchicElement> elements = map.get(hash);
-//
-// for(
-// IHierarchicElement element_b:elements)
-// {
-//
-// List<String> element_a_input = new ArrayList<String>();
-// List<String> element_b_input = new ArrayList<String>();
-// List<String> element_a_output = new ArrayList<String>();
-// List<String> element_b_output = new ArrayList<String>();
-//
-// for(IConnector connector : element.getConnectors()) {
-// PortSpecification port = (PortSpecification)connector.getSpecifications().get(0);
-// String type = port.getType().getClass().getSimpleName();
-// if(connector instanceof InputPort) {
-// element_a_input.add(type);
-// } else {
-// element_a_output.add(type);
-// }
-// }
-//
-// for(IConnector connector : element_b.getConnectors()) {
-// PortSpecification port = (PortSpecification)connector.getSpecifications().get(0);
-// String type = port.getType().getClass().getSimpleName();
-// if(connector instanceof InputPort) {
-// element_b_input.add(type);
-// } else {
-// element_b_output.add(type);
-// }
-// }
-//
-// boolean equals = true;
-//
-// for(String type_a_input : element_a_input) {
-// if(!element_b_input.remove(type_a_input)) {
-// equals = false;
-// break;
-// }
-//
-// }
-//
-// for(String type_a_output : element_a_output) {
-// if(!element_b_output.remove(type_a_output)) {
-// equals = false;
-// break;
-// }
-//
-// }
-// if(equals) {
-// System.out
-// .println("Found duplicate: " + ((INamedCommentedElement)element).getName() +
-// ", " + ((INamedCommentedElement)element_b).getName());
-// break;
-// } else {
-// System.out.println("Same but not duplicate");
-// }
-// }elements.add(element);
-// }
-
-/*
- * public class CommentCompleteness extends MultiMethodDemo {
- * private int total_amount;
- * private int with_comments;
- * 
- * public CommentCompleteness() {
- * total_amount = 0;
- * with_comments = 0;
- * }
- * 
- * @Override
- * public void consume(IHierarchicElement element) {
- * total_amount++;
- * }
- * 
- * @Override
- * public void consume(INamedCommentedElement element) {
- * if(element.getComment() != "") {
- * with_comments++;
- * }
- * total_amount++;
- * }
- * }
- */
-/*
- * public class Tuple<T1, T2> {
- * private T1 element1;
- * private T2 element2;
- * 
- * public Tuple(T1 element1, T2 element2) {
- * this.element1 = element1;
- * this.element2 = element2;
- * }
- * 
- * public T1 getElement1() {
- * return element1;
- * }
- * 
- * public T2 getElement2() {
- * return element2;
- * }
- * }
- */
-/*
- * public void printShare(HierarchicElementBase element) {
- * 
- * Set<Tuple<String, Integer>> counts = new HashSet<>();
- * this.apply(element);
- * counts.add(new Tuple<>("[Self]" + element.getName(), count));
- * count = 0;
- * 
- * for(IHierarchicElement child : element.getContainedElements()) {
- * 
- * HierarchicElementBase real_child = (HierarchicElementBase)child;
- * 
- * recursiveDescent(real_child, this);
- * 
- * counts.add(new Tuple<>(real_child.getName(), count));
- * count = 0;
- * }
- * 
- * double total = counts.stream().mapToInt(t -> t.getElement2()).sum();
- * 
- * System.out.println("[" + this.getClass().getSimpleName() + "] shares:");
- * for(Tuple<String, Integer> tuple : counts) {
- * System.out.println("\t " + String.format("%05.2f%%", tuple.element2 / total * 100) +
- * ", " + tuple.element2 + ": " + tuple.element1);
- * }
- * }
- */
-
-/*
- * protected void recursiveDescent(HierarchicElementBase element, CounterConsumer consumer) {
- * consumer.apply(element);
- * 
- * for(IHierarchicElement child : element.getContainedElements()) {
- * HierarchicElementBase real_child = (HierarchicElementBase)child;
- * recursiveDescent(real_child, consumer);
- * }
- * }
- */
-
-/*
- * public class ConnectionCounter {
- * public void apply(IHierarchicElement element) {
- * count += element.getConnections().size();
- * }
- * 
- * }
- * 
- * private void extractComment(IHierarchicElement c) {
- * strings.add(((INamedCommentedElement)c).getComment());
- * }
- * }
- * }
- */
+	/*
+	 * 
+	 * CLONE DETECTION START public class CloneDetection {
+	 * 
+	 * private Map<Integer, List<IHierarchicElement>> map = new HashMap<>();
+	 * 
+	 * public void printResult() { System.out.println("Stuff"); }
+	 * 
+	 * public void apply(IHierarchicElement element) { int hash = 1; for(IConnector
+	 * connector : element.getConnectors()) { EList<IModelElementSpecification>
+	 * specifications = connector.getSpecifications(); if(!specifications.isEmpty()
+	 * && connector.getSpecifications().get(0) instanceof PortSpecification) {
+	 * 
+	 * PortSpecification port =
+	 * (PortSpecification)connector.getSpecifications().get(0); hash = 31 * hash +
+	 * (connector instanceof InputPort ? 1 : 2) *
+	 * port.getType().getClass().hashCode(); } else { // Clone Detection for State
+	 * diagrams not supported return; } }map.putIfAbsent(hash,new ArrayList<>());
+	 * 
+	 * List<IHierarchicElement> elements = map.get(hash);
+	 * 
+	 * for( IHierarchicElement element_b:elements) {
+	 * 
+	 * List<String> element_a_input = new ArrayList<String>(); List<String>
+	 * element_b_input = new ArrayList<String>(); List<String> element_a_output =
+	 * new ArrayList<String>(); List<String> element_b_output = new
+	 * ArrayList<String>();
+	 * 
+	 * for(IConnector connector : element.getConnectors()) { PortSpecification port
+	 * = (PortSpecification)connector.getSpecifications().get(0); String type =
+	 * port.getType().getClass().getSimpleName(); if(connector instanceof InputPort)
+	 * { element_a_input.add(type); } else { element_a_output.add(type); } }
+	 * 
+	 * for(IConnector connector : element_b.getConnectors()) { PortSpecification
+	 * port = (PortSpecification)connector.getSpecifications().get(0); String type =
+	 * port.getType().getClass().getSimpleName(); if(connector instanceof InputPort)
+	 * { element_b_input.add(type); } else { element_b_output.add(type); } }
+	 * 
+	 * boolean equals = true;
+	 * 
+	 * for(String type_a_input : element_a_input) {
+	 * if(!element_b_input.remove(type_a_input)) { equals = false; break; }
+	 * 
+	 * }
+	 * 
+	 * for(String type_a_output : element_a_output) {
+	 * if(!element_b_output.remove(type_a_output)) { equals = false; break; }
+	 * 
+	 * } if(equals) { System.out .println("Found duplicate: " +
+	 * ((INamedCommentedElement)element).getName() + ", " +
+	 * ((INamedCommentedElement)element_b).getName()); break; } else {
+	 * System.out.println("Same but not duplicate"); } }elements.add(element); }
+	 * CLONE DETECTION END
+	 * 
+	 * 
+	 * public void printShare(HierarchicElementBase element) {
+	 * 
+	 * Set<Tuple<String, Integer>> counts = new HashSet<>(); this.apply(element);
+	 * counts.add(new Tuple<>("[Self]" + element.getName(), count)); this.count = 0;
+	 * 
+	 * for(IHierarchicElement child : element.getContainedElements()) {
+	 * 
+	 * HierarchicElementBase real_child = (HierarchicElementBase)child;
+	 * 
+	 * recursiveDescent(real_child, this);
+	 * 
+	 * counts.add(new Tuple<>(real_child.getName(), count)); count = 0; }
+	 * 
+	 * double total = counts.stream().mapToInt(t -> t.getElement2()).sum();
+	 * 
+	 * System.out.println("[" + this.getClass().getSimpleName() + "] shares:");
+	 * for(Tuple<String, Integer> tuple : counts) { System.out.println("\t " +
+	 * String.format("%05.2f%%", tuple.element2 / total * 100) + ", " +
+	 * tuple.element2 + ": " + tuple.element1); } }
+	 * 
+	 */
+}
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 2fa1be0c7..a14e4e0f2 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
@@ -107,13 +107,20 @@ public class ModelQualityService extends EObjectAwareServiceBase<IModelQualityPr
 	 */
 	public List<IModelQualityProvider<? extends EObject>> performMetricAnalysis(FileProject fp) {
 		List<IModelQualityProvider<? extends EObject>> result =
-				new LinkedList<IModelQualityProvider<? extends EObject>>();
+				new LinkedList<>();
 		for(IProjectRootElement ele : fp.getRootElements()) {
 			if(ele instanceof IHierarchicElement) {
+				
+				//TODO check get(0)
+				IHierarchicElement firstNode = ((IHierarchicElement) ele).getContainedElements().get(0);
+				
 				HierarchicElementSizeProvider hes =
-						new HierarchicElementSizeProvider(ele.getName());
-				hes.apply((IHierarchicElement)ele);
-				System.out.println("checked in hierarchic metrics for: " + hes.getName());
+						new HierarchicElementSizeProvider();
+				hes.apply(firstNode);
+				System.out.println("checked in hierarchic metrics for: " + ele.getName());
+				double commentable = hes.getStoredMetrics().getOrDefault(HierarchicElementSizeProvider.NUMBER_OF_TOTAL_COMMENTABLE_ELEMENTS, 0.0);
+				double commented = hes.getStoredMetrics().getOrDefault(HierarchicElementSizeProvider.NUMBER_OF_TOTAL_COMMENTED_ELEMENTS, 0.0);
+				System.out.println("Commented to total: "+commented+", "+commentable+", "+commented/commentable);
 				result.add(hes);
 			}
 		}
@@ -134,6 +141,7 @@ public class ModelQualityService extends EObjectAwareServiceBase<IModelQualityPr
 		// metricsList.addAll(metrics);
 		// }
 		// }
+		
 		return result;
 	}
 
-- 
GitLab