Skip to content
Snippets Groups Projects
Commit ebd4c9a2 authored by Eddie Groh's avatar Eddie Groh
Browse files

Refactored metric collection to proper provider pattern

Issue-Ref: 4310
Issue-Url: af3#4310



Signed-off-by: default avatarEddie Groh <groh@fortiss.org>
parent a4d26fb0
No related branches found
No related tags found
1 merge request!210Setting up Metric extraction plugin for AF3 : Issue 4310
Showing with 112 additions and 89 deletions
......@@ -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
......@@ -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) {
......
......@@ -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
......@@ -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} */
......
......@@ -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);
}
}
......@@ -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);
}
......@@ -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);
......
......@@ -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() {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment