From ebd4c9a2e525d883d95c0054ccdad71948612fe2 Mon Sep 17 00:00:00 2001 From: Eddie Groh <groh@fortiss.org> Date: Mon, 10 Jul 2023 18:36:27 +0200 Subject: [PATCH] Refactored metric collection to proper provider pattern 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 + .../quality/ui/ModelQualityUIActivator.java | 6 +- .../META-INF/MANIFEST.MF | 1 + .../ext/quality/AF3QualityActivator.java | 4 +- .../quality/HierarchicElementProvider.java | 89 +++--------------- .../tooling/ext/quality/IMetricProvider.java | 3 +- .../quality/service/IModelQualityService.java | 4 +- .../quality/service/ModelQualityService.java | 92 +++++++++++++++++-- 8 files changed, 112 insertions(+), 89 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 1da1df17e..22556059e 100644 --- a/org.fortiss.tooling.ext.quality.ui/META-INF/MANIFEST.MF +++ b/org.fortiss.tooling.ext.quality.ui/META-INF/MANIFEST.MF @@ -14,3 +14,5 @@ Require-Bundle: org.eclipse.ui.ide;visibility:=reexport, org.eclipse.emf.ecore, org.fortiss.af3.project;bundle-version="2.23.0" Export-Package: org.fortiss.tooling.ext.quality.ui.view.fx +Bundle-Activator: org.fortiss.tooling.ext.quality.ui.ModelQualityUIActivator +Bundle-ActivationPolicy: lazy diff --git a/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/ModelQualityUIActivator.java b/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/ModelQualityUIActivator.java index 0248951db..2a6eea8fe 100644 --- a/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/ModelQualityUIActivator.java +++ b/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/ModelQualityUIActivator.java @@ -23,6 +23,7 @@ public class ModelQualityUIActivator extends Plugin { public void start(BundleContext context) throws Exception { super.start(context); plugin = this; + System.out.println("[Plugin] " + PLUGIN_ID + " started."); } /** {@inheritDoc} */ @@ -35,7 +36,7 @@ public class ModelQualityUIActivator extends Plugin { /** * Returns the shared instance. * - * @return The shared instance of ToolingReuseActivator + * @return The shared instance of ModelQualityUIActivator */ public static ModelQualityUIActivator getDefault() { return plugin; @@ -44,7 +45,8 @@ public class ModelQualityUIActivator extends Plugin { /** * Returns the image descriptor for the given icon file. * - * @param path The path to the icon file of the image descriptor + * @param path + * The path to the icon file of the image descriptor * @return The image descriptor */ public static ImageDescriptor getImageDescriptor(String path) { diff --git a/org.fortiss.tooling.ext.quality/META-INF/MANIFEST.MF b/org.fortiss.tooling.ext.quality/META-INF/MANIFEST.MF index 9b9be8e7a..31fb47eef 100644 --- a/org.fortiss.tooling.ext.quality/META-INF/MANIFEST.MF +++ b/org.fortiss.tooling.ext.quality/META-INF/MANIFEST.MF @@ -15,4 +15,5 @@ Require-Bundle: org.eclipse.core.runtime, Export-Package: org.fortiss.tooling.ext.quality, org.fortiss.tooling.ext.quality.data, org.fortiss.tooling.ext.quality.service +Bundle-ActivationPolicy: lazy 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 9debc4bb2..3c8aaf351 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 @@ -41,8 +41,8 @@ public class AF3QualityActivator extends Plugin { plugin = this; System.out.println("[Plugin] " + PLUGIN_ID + " started."); ModelQualityService.getInstance().startService(); - IModelQualityService.getInstance().registerMetricProvider( - new HierarchicElementProvider(), IHierarchicElement.class); + IModelQualityService.getInstance().registerMetricProvider(new HierarchicElementProvider(), + IHierarchicElement.class); } /** {@inheritDoc} */ diff --git a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/HierarchicElementProvider.java b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/HierarchicElementProvider.java index 7008b8eb3..16b732c97 100644 --- a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/HierarchicElementProvider.java +++ b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/HierarchicElementProvider.java @@ -15,13 +15,9 @@ +--------------------------------------------------------------------------*/ package org.fortiss.tooling.ext.quality; -import java.util.Optional; - -import org.eclipse.emf.common.util.EList; import org.fortiss.tooling.base.model.base.EntryConnectorBase; import org.fortiss.tooling.base.model.base.ExitConnectorBase; 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; @@ -56,64 +52,26 @@ public class HierarchicElementProvider implements IMetricProvider<IHierarchicEle /** {@inheritDoc} */ @Override - public void apply(MetricDataManager manager, MetricTreeNode node, - IHierarchicElement currentElement) { + public void collectMetrics(MetricTreeNode node, IHierarchicElement currentElement) { var metrics = node.getStoredMetrics(); - boolean isElementCommentable = currentElement instanceof INamedCommentedElement; - metrics.put(MetricKey.NUMBER_OF_TOTAL_COMMENTABLE_ELEMENTS, - isElementCommentable ? 1.0 : 0.0); - String comment = - isElementCommentable ? ((INamedCommentedElement)currentElement).getComment() : null; - metrics.put(MetricKey.NUMBER_OF_TOTAL_COMMENTED_ELEMENTS, - comment != null && comment != "" ? 1.0 : 0.0); - if(isElementCommentable) { - node.setName(((INamedCommentedElement)currentElement).getName()); - } else { - node.setName("Unnamable Element"); - } - - // Check if any of the specifications is an IHierarchicElement - // This is for example the case with an StateAutomaton - Optional<IHierarchicElement> hierarchicElementOptional = currentElement.getSpecifications() - .stream().filter(s -> s instanceof IHierarchicElement) - .map(s -> (IHierarchicElement)s).findAny(); - if(hierarchicElementOptional.isPresent()) { - // Do not collect statistics for the current element, but instead collect them for the - // specification - IHierarchicElement specificationElement = hierarchicElementOptional.get(); - EList<IHierarchicElement> containedElements = - specificationElement.getContainedElements(); - if(containedElements.size() == 1) { - // Add reference from the element to this, so the lookups works as expected - manager.getHierarchicLookupTable().put(specificationElement, node); - // Skip the specification element to get a more useful tree structure - this.applyMetrics(manager, node, containedElements.get(0)); + if(node.getName() == null) { + boolean isElementCommentable = currentElement instanceof INamedCommentedElement; + metrics.put(MetricKey.NUMBER_OF_TOTAL_COMMENTABLE_ELEMENTS, + isElementCommentable ? 1.0 : 0.0); + String comment = isElementCommentable + ? ((INamedCommentedElement)currentElement).getComment() : null; + metrics.put(MetricKey.NUMBER_OF_TOTAL_COMMENTED_ELEMENTS, + comment != null && comment != "" ? 1.0 : 0.0); + if(isElementCommentable) { + node.setName(((INamedCommentedElement)currentElement).getName()); } else { - this.applyMetrics(manager, node, specificationElement); + node.setName("Unnamable Element"); } - // Add reference from the element to this, so the lookups works as expected - manager.getHierarchicLookupTable().put(currentElement, node); - return; - } - this.applyMetrics(manager, node, currentElement); - } - - /** - * @param manager - * for saving the lookup data - * @param node - * for saving the metric data - * @param currentElement - * the element on which to collect data - */ - private void applyMetrics(MetricDataManager manager, MetricTreeNode node, - IHierarchicElement currentElement) { - var metrics = node.getStoredMetrics(); - - metrics.put(MetricKey.UNQIUE_ID, (currentElement instanceof IIdLabeled) - ? ((IIdLabeled)currentElement).getId() : -1.0); + metrics.put(MetricKey.UNQIUE_ID, (currentElement instanceof IIdLabeled) + ? ((IIdLabeled)currentElement).getId() : -1.0); + } var connectors = currentElement.getConnectors(); metrics.put(MetricKey.NUMBER_OF_CONNECTORS, (double)connectors.size()); @@ -132,22 +90,5 @@ public class HierarchicElementProvider implements IMetricProvider<IHierarchicEle metrics.put(MetricKey.NUMBER_OF_TOTAL_LEAF_ELEMENTS, currentElement.getContainedElements().size() == 0 ? 1.0 : 0.0); - - for(IHierarchicElement containedElement : currentElement.getContainedElements()) { - MetricTreeNode child = new MetricTreeNode(); - node.getChildren().add(child); - apply(manager, child, containedElement); - - for(MetricKey key : new MetricKey[] {MetricKey.NUMBER_OF_TOTAL_CONNECTORS, - MetricKey.NUMBER_OF_TOTAL_ENTRY_CONNECTORS, - MetricKey.NUMBER_OF_TOTAL_EXIT_CONNECTORS, 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); - } - } - - manager.getHierarchicLookupTable().put(currentElement, node); } } diff --git a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/IMetricProvider.java b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/IMetricProvider.java index 01f3d4d7d..43606a0df 100644 --- a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/IMetricProvider.java +++ b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/IMetricProvider.java @@ -16,7 +16,6 @@ package org.fortiss.tooling.ext.quality; import org.eclipse.emf.ecore.EObject; -import org.fortiss.tooling.ext.quality.data.MetricDataManager; import org.fortiss.tooling.ext.quality.data.MetricTreeNode; import org.fortiss.tooling.ext.quality.service.IModelQualityService; import org.fortiss.tooling.kernel.service.base.IEObjectAware; @@ -31,5 +30,5 @@ import org.fortiss.tooling.kernel.service.base.IEObjectAware; public interface IMetricProvider<C extends EObject> extends IEObjectAware<EObject> { /** Applies the IMetricProvider to the given model element. */ - void apply(MetricDataManager manager, MetricTreeNode node, C element); + void collectMetrics(MetricTreeNode node, C element); } diff --git a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/service/IModelQualityService.java b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/service/IModelQualityService.java index 5400dc318..025bc2e75 100644 --- a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/service/IModelQualityService.java +++ b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/service/IModelQualityService.java @@ -15,6 +15,7 @@ +--------------------------------------------------------------------------*/ package org.fortiss.tooling.ext.quality.service; +import org.eclipse.emf.ecore.EObject; import org.fortiss.tooling.ext.quality.IMetricProvider; import org.fortiss.tooling.kernel.extension.data.ITopLevelElement; @@ -30,7 +31,8 @@ public interface IModelQualityService { } /** Registers the metric provider with the service. */ - void registerMetricProvider(IMetricProvider<?> provider, Class<?> modelElementClass); + <T extends EObject> void registerMetricProvider(IMetricProvider<T> provider, + Class<T> modelElementClass); /** analyses the metrics and processes them */ void performMetricAnalysis(ITopLevelElement top); 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 f02363a74..96f6737ad 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 @@ -16,7 +16,6 @@ package org.fortiss.tooling.ext.quality.service; import static java.util.Collections.emptyList; -import static org.fortiss.tooling.kernel.utils.EcoreUtils.getFirstChildWithType; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -33,13 +32,13 @@ import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; 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.HierarchicElementProvider; import org.fortiss.tooling.ext.quality.IMetricProvider; import org.fortiss.tooling.ext.quality.data.MetricDataManager; import org.fortiss.tooling.ext.quality.data.MetricKey; @@ -91,8 +90,8 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider /** Registers the migration provider with the service. */ @Override - public void registerMetricProvider(IMetricProvider<?> provider, - Class<?> modelElementClass) { + public <T extends EObject> void registerMetricProvider(IMetricProvider<T> provider, + Class<T> modelElementClass) { addHandler(modelElementClass, provider); } @@ -110,7 +109,7 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider protected List<IMetricProvider<?>> getAllMetricProviders(EObject input) { List<IMetricProvider<?>> providers = new ArrayList<>(); for(Entry<Class<?>, List<IMetricProvider<?>>> migEntry : handlerMap.entrySet()) { - if(getFirstChildWithType(input, migEntry.getKey()) != null) { + if(migEntry.getKey().isAssignableFrom(input.getClass())) { providers.addAll(migEntry.getValue()); } } @@ -137,10 +136,9 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider var root_nodes = metricDataManagerInstance.getRootNodes(); // Get first element, there should not be any other elements - IHierarchicElement firstNode = elements.get(0); + IHierarchicElement firstElement = elements.get(0); MetricTreeNode root_node = new MetricTreeNode(); - HierarchicElementProvider hes = new HierarchicElementProvider(); - hes.apply(metricDataManagerInstance, root_node, firstNode); + recursivlyCollectMetrics(root_node, firstElement); root_nodes.put(rootElement, root_node); } } @@ -148,6 +146,84 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider metricExtractionToCSV(metricDataManagerInstance.getRootNodes()); } + /** + * @param node + * to which the data is collected + * @param currentElement + * element to collect the data from + */ + private void recursivlyCollectMetrics(MetricTreeNode node, IHierarchicElement currentElement) { + + var manager = metricDataManagerInstance; + + collectMetrics(node, currentElement); + + // Check if any of the specifications is an IHierarchicElement + // This is for example the case with an StateAutomaton + Optional<IHierarchicElement> hierarchicElementOptional = currentElement.getSpecifications() + .stream().filter(s -> s instanceof IHierarchicElement) + .map(s -> (IHierarchicElement)s).findAny(); + if(hierarchicElementOptional.isPresent()) { + // Do not collect statistics for the current element, but instead collect them for the + // specification + IHierarchicElement specificationElement = hierarchicElementOptional.get(); + EList<IHierarchicElement> containedElements = + specificationElement.getContainedElements(); + if(containedElements.size() == 1) { + // Add reference from the element to this, so the lookups works as expected + manager.getHierarchicLookupTable().put(specificationElement, node); + // Skip the specification element to get a more useful tree structure + recursivlyCollectMetrics(node, containedElements.get(0)); + } else { + recursivlyCollectMetrics(node, specificationElement); + } + // Add reference from the element to this, so the lookups works as expected + manager.getHierarchicLookupTable().put(currentElement, node); + } else { + + // Iterate over all children and + for(IHierarchicElement containedElement : currentElement.getContainedElements()) { + MetricTreeNode child = new MetricTreeNode(); + node.getChildren().add(child); + recursivlyCollectMetrics(child, containedElement); + + for(MetricKey key : new MetricKey[] {MetricKey.NUMBER_OF_TOTAL_CONNECTORS, + MetricKey.NUMBER_OF_TOTAL_ENTRY_CONNECTORS, + MetricKey.NUMBER_OF_TOTAL_EXIT_CONNECTORS, + MetricKey.NUMBER_OF_TOTAL_ELEMENTS, + MetricKey.NUMBER_OF_TOTAL_COMMENTABLE_ELEMENTS, + MetricKey.NUMBER_OF_TOTAL_COMMENTED_ELEMENTS, + MetricKey.NUMBER_OF_TOTAL_LEAF_ELEMENTS}) { + node.getStoredMetrics().merge(key, child.getStoredMetrics().get(key), + Double::sum); + } + } + + manager.getHierarchicLookupTable().put(currentElement, node); + } + } + + /** + * @param node + * to which the data is collected + * @param element + * element to collect the data from + */ + @SuppressWarnings("unchecked") + private void collectMetrics(MetricTreeNode node, IHierarchicElement element) { + + List<IMetricProvider<?>> providers = getAllMetricProviders(element); + + if(providers.isEmpty()) { + System.out.println("KATASTROPHE"); + getAllMetricProviders(element); + } + + for(IMetricProvider<?> provider : providers) { + ((IMetricProvider<EObject>)provider).collectMetrics(node, element); + } + } + /** */ @Override protected String getExtensionPointName() { -- GitLab