diff --git a/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/.ratings b/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/.ratings index 4f312f29ea643d2e9de0b03a9599c5e45bcb11a6..10f0daaec44f813e289261c07dfbc3e7864a10a4 100644 --- a/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/.ratings +++ b/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/.ratings @@ -1,2 +1,2 @@ -ModelQualityExtractionMenu.java e2926b47f4f30adb160c47aef773853bb5b03fcb RED +ModelQualityExtractionMenu.java 3bdbf3d37715539648af8ba7feefbec9370c4dc4 YELLOW ModelQualityUIActivator.java 2f47db82bc088072dbfe53f82d3ed417d77fd23c GREEN diff --git a/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/ModelQualityExtractionMenu.java b/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/ModelQualityExtractionMenu.java index e2926b47f4f30adb160c47aef773853bb5b03fcb..3bdbf3d37715539648af8ba7feefbec9370c4dc4 100644 --- a/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/ModelQualityExtractionMenu.java +++ b/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/ModelQualityExtractionMenu.java @@ -27,7 +27,6 @@ import org.eclipse.jface.action.Action; import org.eclipse.jface.action.ActionContributionItem; import org.eclipse.jface.action.IContributionItem; import org.eclipse.jface.resource.ImageDescriptor; -import org.fortiss.af3.project.model.FileProject; import org.fortiss.tooling.ext.quality.service.IModelQualityService; import org.fortiss.tooling.kernel.extension.data.ITopLevelElement; import org.fortiss.tooling.kernel.service.IPersistencyService; @@ -48,14 +47,11 @@ public class ModelQualityExtractionMenu implements IContextMenuContributor { @Override public List<IContributionItem> getContributedItems(EObject selection, ContextMenuContextProvider contextProvider) { - // TODO (SB): Use of FileProject must be avoided - // Change the condition to "selection.eContainer() != null" (only FileProjects) - // have a null parent and remove dependency to org.fortiss.af3.project from this plugin - if(!(selection instanceof FileProject)) { + if(!(selection.eContainer() != null)) { return emptyList(); } return asList(new IContributionItem[] { - new ActionContributionItem(new MetricExtractionAction((FileProject)selection))}); + new ActionContributionItem(new MetricExtractionAction(selection))}); } /** {@inheritDoc} */ @@ -73,10 +69,10 @@ public class ModelQualityExtractionMenu implements IContextMenuContributor { protected class MetricExtractionAction extends Action { /** {@link FileProject} on which the action will be triggered. */ - private final FileProject fp; + private final EObject fp; /** Constructor. */ - public MetricExtractionAction(FileProject fp) { + public MetricExtractionAction(EObject fp) { super(MENU_NAME, getActionIcon()); this.fp = fp; } diff --git a/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/view/fx/.ratings b/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/view/fx/.ratings index 1b3e6d88619686bf341ccc8127b8ce859df73108..c0833d43f2c31c67a1207e45a66bcfe587ccb023 100644 --- a/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/view/fx/.ratings +++ b/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/view/fx/.ratings @@ -1,3 +1,3 @@ IModelQualityViewPart.java 708f8089645df12098ea67190805cce343045d2e GREEN -ModelQualityFXController.java f4ae42467509d29326bdabe822310083253910dc RED -ModelQualityFXViewPart.java 4f142d1b04ab9e5f0ce54ff248fe0abf6f141937 RED +ModelQualityFXController.java 67bb0a067c578ac9a9b30e5973587cc57374a782 YELLOW +ModelQualityFXViewPart.java a1e82fe68a3fe7d813fa61d5148ffcd1592000f7 YELLOW diff --git a/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/view/fx/ModelQualityFXController.java b/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/view/fx/ModelQualityFXController.java index f4ae42467509d29326bdabe822310083253910dc..67bb0a067c578ac9a9b30e5973587cc57374a782 100644 --- a/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/view/fx/ModelQualityFXController.java +++ b/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/view/fx/ModelQualityFXController.java @@ -18,6 +18,7 @@ package org.fortiss.tooling.ext.quality.ui.view.fx; import static javafx.scene.paint.Color.BLUE; import static javafx.scene.paint.Color.DARKGRAY; import static javafx.scene.paint.Color.LIGHTGRAY; +import static java.util.stream.Collectors.toList; import static org.fortiss.tooling.common.ui.javafx.style.FontStyle.BLACK_VERDANA_10PT; import static org.fortiss.tooling.common.ui.javafx.style.FontStyle.BLACK_VERDANA_12PT; import static org.fortiss.tooling.common.ui.javafx.style.FontStyle.BLACK_VERDANA_14PT; @@ -26,13 +27,14 @@ import static org.fortiss.tooling.common.ui.javafx.style.LineStyle.SOLID_BLACK_1 import static org.fortiss.tooling.kernel.ui.util.SelectionUtils.checkAndPickFirst; import static org.fortiss.tooling.kernel.utils.EcoreUtils.getFirstParentWithType; + import java.text.DecimalFormat; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.stream.Collectors; + import org.eclipse.emf.ecore.EObject; import org.eclipse.jface.viewers.ISelection; @@ -43,10 +45,10 @@ 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.IMetricUpdateListener; -import org.fortiss.tooling.ext.quality.data.MetricDataManager; +import org.fortiss.tooling.ext.quality.data.MetricData; 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.ext.quality.service.IModelQualityService; import org.fortiss.tooling.kernel.model.IProjectRootElement; import org.fortiss.tooling.spiderchart.control.SpiderChartViewer; import org.fortiss.tooling.spiderchart.model.DataSeries; @@ -151,11 +153,7 @@ public class ModelQualityFXController extends CompositeFXControllerBase<SplitPan // Invalidate last selection, so if no new selection is found the charts are cleared lastSelectedElement = null; - // TODO (SB): Unneeded? - ModelQualityService.getInstance(); - - // TODO (SB): Use IModelQualityService - var manager = ModelQualityService.getInstance().getMetricDataManagerInstance(); + IModelQualityService mqs = IModelQualityService.getInstance(); EObject selected = checkAndPickFirst(selection, EObject.class); @@ -172,8 +170,7 @@ public class ModelQualityFXController extends CompositeFXControllerBase<SplitPan updateCharts("Selection does not have a project root element."); return; } - - var rootDataElement = manager.getDataRootElementMap().get(currentRootElement); + var rootDataElement = mqs.getMetricData().getDataRootElementMap().get(currentRootElement); if(rootDataElement == null) { bottomText.setText( @@ -212,9 +209,9 @@ public class ModelQualityFXController extends CompositeFXControllerBase<SplitPan private void updateCharts(String message) { if(lastSelectedElement != null) { - MetricDataManager manager = - ModelQualityService.getInstance().getMetricDataManagerInstance(); - MetricTreeNode node = manager.getTreeNodeLookupTable().get(lastSelectedElement); + MetricData metricData = + IModelQualityService.getInstance().getMetricData(); + MetricTreeNode node = metricData.getTreeNodeLookupTable().get(lastSelectedElement); if(node != null) { @@ -343,10 +340,12 @@ public class ModelQualityFXController extends CompositeFXControllerBase<SplitPan } // Create DataSeries for all elements - // TODO (SB): Use static import for toList() List<Pair<MetricTreeNode, DataSeries>> dataSeriesList = lastViewedElements.stream() - .map(pair -> new Pair<>(pair.getKey(), new DataSeries(pair.getKey().getName()))) - .collect(Collectors.toList()); + .map(pair -> new Pair<>(pair.getKey(), + (pair.getKey().getName() == null) ? new DataSeries("No Name found") : new DataSeries(pair.getKey().getName()) + )) + .collect(toList()); + // Create SpiderChart and set basic styling SpiderChart spiderChart = new SpiderChart(); @@ -381,11 +380,9 @@ public class ModelQualityFXController extends CompositeFXControllerBase<SplitPan } // Iterate over all dataSeries and add them to the spider chart - // TODO (SB): Iterate over collection. get(i) is expensive. "for(var pair : dataSeriesList)" - for(int i = 0; i < dataSeriesList.size(); i++) { - var pair = dataSeriesList.get(i); + int i = 0; + for(var pair : dataSeriesList) { spiderChart.addData(pair.getValue()); - // Assign different colors to different data series Color color = SPIDER_CHART_OVERLAY_COLORS[i]; LineStyle olive1pt = new LineStyle(color); @@ -393,6 +390,7 @@ public class ModelQualityFXController extends CompositeFXControllerBase<SplitPan DataSeriesStyle style = new DataSeriesStyle(olive1pt, oliveFill, true, true, BLACK_VERDANA_10PT, 7, new DecimalFormat("#.#")); chartStyle.setDataSeriesStyle(pair.getValue(), style); + i++; } // Configure legend @@ -419,7 +417,7 @@ public class ModelQualityFXController extends CompositeFXControllerBase<SplitPan // Store IModelQualityService.getInstance() (sic!) in a variable (e.g. "mqs") for // readability - var rootDataElement = ModelQualityService.getInstance().getMetricDataManagerInstance() + var rootDataElement = IModelQualityService.getInstance().getMetricData() .getDataRootElementMap().get(updatedElement); if(rootDataElement != null) { bottomText.setText("Metrics last updated: " + diff --git a/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/view/fx/ModelQualityFXViewPart.java b/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/view/fx/ModelQualityFXViewPart.java index 4f142d1b04ab9e5f0ce54ff248fe0abf6f141937..a1e82fe68a3fe7d813fa61d5148ffcd1592000f7 100644 --- a/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/view/fx/ModelQualityFXViewPart.java +++ b/org.fortiss.tooling.ext.quality.ui/src/org/fortiss/tooling/ext/quality/ui/view/fx/ModelQualityFXViewPart.java @@ -28,6 +28,8 @@ import javafx.scene.Scene; public class ModelQualityFXViewPart extends AF3FXViewPart implements IModelQualityViewPart { // TODO (SB): Is there a reason to make the controller static? (also rename to viewController) + // FIXME (KB): Naming convention and static taken from reuse library. So you want me to change the FX controller class to viewController? + // Would result in inconsistent use otherwise. still change it and add the view controller as parameter for instancing a View Part? /** The FX Controller for this view. */ private static final ModelQualityFXController VIEW_CONTROLLER = new ModelQualityFXController(); diff --git a/org.fortiss.tooling.ext.quality/META-INF/MANIFEST.MF b/org.fortiss.tooling.ext.quality/META-INF/MANIFEST.MF index 31f41cf5677a20cf1922a03b13a140e2455fb8d4..730b39560b4c2ad54dd97284b1747ed12c47830e 100644 --- a/org.fortiss.tooling.ext.quality/META-INF/MANIFEST.MF +++ b/org.fortiss.tooling.ext.quality/META-INF/MANIFEST.MF @@ -6,7 +6,7 @@ Bundle-Version: 2.23.0.qualifier Automatic-Module-Name: org.fortiss.tooling.ext.quality Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-Vendor: fortiss GmbH -Bundle-Activator: org.fortiss.tooling.ext.quality.AF3QualityActivator +Bundle-Activator: org.fortiss.tooling.ext.quality.ModelQualityActivator Require-Bundle: org.eclipse.core.runtime, org.eclipse.emf.ecore;visibility:=reexport, org.fortiss.tooling.base;visibility:=reexport, diff --git a/org.fortiss.tooling.ext.quality/html/developer/.ratings b/org.fortiss.tooling.ext.quality/html/developer/.ratings index b1f9061030d5d87f34d41998eba0091beef2e7af..b6a7b0b9a451d3f77d0cc60408f1a26daead3cf3 100644 --- a/org.fortiss.tooling.ext.quality/html/developer/.ratings +++ b/org.fortiss.tooling.ext.quality/html/developer/.ratings @@ -1 +1 @@ -documentation.html f102e6b3757eec158de9bf78238e2865d01de2a4 RED +documentation.html b66c2bfb495047a8e4b680b02231ab2fdb34cec3 YELLOW diff --git a/org.fortiss.tooling.ext.quality/html/developer/documentation.html b/org.fortiss.tooling.ext.quality/html/developer/documentation.html index f102e6b3757eec158de9bf78238e2865d01de2a4..b66c2bfb495047a8e4b680b02231ab2fdb34cec3 100644 --- a/org.fortiss.tooling.ext.quality/html/developer/documentation.html +++ b/org.fortiss.tooling.ext.quality/html/developer/documentation.html @@ -15,7 +15,6 @@ <table border="1"> <thead> <tr> - <th>Number</th> <th>Provider</th> <th>Qualified Name</th> <th>Metric</th> @@ -25,95 +24,83 @@ </thead> <tbody> <tr> - <td>1</td> - <td>HierarchicElementProvider</td> - <td>org.fortiss.tooling.ext.quality.HierarchicElementProvider</td> + <td>HierarchicElementMetricProvider</td> + <td>org.fortiss.tooling.ext.quality.HierarchicElementMetricProvider</td> <td>UNIQUE_ID</td> <td>Integer</td> <td>This is an unique identifier for each element as specified in org.fortiss.tooling.kernel.model.IIdLabeled.</td> </tr> <tr> - <td>2</td> - <td>HierarchicElementProvider</td> - <td>org.fortiss.tooling.ext.quality.HierarchicElementProvider</td> + <td>HierarchicElementMetricProvider</td> + <td>org.fortiss.tooling.ext.quality.HierarchicElementMetricProvider</td> <td>NUMBER_OF_CONNECTORS</td> <td>Integer</td> <td>Number of connectors in the respective element.</td> </tr> <tr> - <td>3</td> - <td>HierarchicElementProvider</td> - <td>org.fortiss.tooling.ext.quality.HierarchicElementProvider</td> + <td>HierarchicElementMetricProvider</td> + <td>org.fortiss.tooling.ext.quality.HierarchicElementMetricProvider</td> <td>NUMBER_OF_CONTAINED_ELEMENTS</td> <td>Integer</td> <td>Number of entries in the containedElements list.</td> </tr> <tr> - <td>4</td> - <td>HierarchicElementProvider</td> - <td>org.fortiss.tooling.ext.quality.HierarchicElementProvider</td> + <td>HierarchicElementMetricProvider</td> + <td>org.fortiss.tooling.ext.quality.HierarchicElementMetricProvider</td> <td>NUMBER_OF_CONNECTIONS</td> <td>Integer</td> <td>Number of connections in this element. List of aggregated connection model elements. Usually aggregates all connections of its direct sub-structure.</td> </tr> <tr> - <td>5</td> - <td>HierarchicElementProvider</td> - <td>org.fortiss.tooling.ext.quality.HierarchicElementProvider</td> + <td>HierarchicElementMetricProvider</td> + <td>org.fortiss.tooling.ext.quality.HierarchicElementMetricProvider</td> <td>NUMBER_OF_TOTAL_CONNECTORS</td> <td>Integer</td> <td>Total number of connectors in this element and all contained elements.</td> </tr> <tr> - <td>6</td> - <td>HierarchicElementProvider</td> - <td>org.fortiss.tooling.ext.quality.HierarchicElementProvider</td> + <td>HierarchicElementMetricProvider</td> + <td>org.fortiss.tooling.ext.quality.HierarchicElementMetricProvider</td> <td>NUMBER_OF_TOTAL_ENTRY_CONNECTORS</td> <td>Integer</td> <td>Sum of all connectors which implement org.fortiss.tooling.base.model.base.EntryConnectorBase.</td> </tr> <tr> - <td>7</td> - <td>HierarchicElementProvider</td> - <td>org.fortiss.tooling.ext.quality.HierarchicElementProvider</td> + <td>HierarchicElementMetricProvider</td> + <td>org.fortiss.tooling.ext.quality.HierarchicElementMetricProvider</td> <td>NUMBER_OF_TOTAL_EXIT_CONNECTORS</td> <td>Integer</td> <td>Sum of all connectors which implement org.fortiss.tooling.base.model.base.ExitConnectorBase. Usually, the sum over this and NUMBER_OF_TOTAL_ENTRY_CONNECTORS should equal NUMBER_OF_TOTAL_CONNECTORS.</td> </tr> <tr> - <td>8</td> - <td>HierarchicElementProvider</td> - <td>org.fortiss.tooling.ext.quality.HierarchicElementProvider</td> + <td>HierarchicElementMetricProvider</td> + <td>org.fortiss.tooling.ext.quality.HierarchicElementMetricProvider</td> <td>NUMBER_OF_TOTAL_ELEMENTS</td> <td>Integer</td> <td>Total number of elements contained in this element. Includes the element for which this metric is recorded.</td> </tr> <tr> - <td>9</td> - <td>HierarchicElementProvider</td> - <td>org.fortiss.tooling.ext.quality.HierarchicElementProvider</td> + <td>HierarchicElementMetricProvider</td> + <td>org.fortiss.tooling.ext.quality.HierarchicElementMetricProvider</td> <td>NUMBER_OF_TOTAL_COMMENTABLE_ELEMENTS</td> <td>Integer</td> <td>Total number of elements implementing org.fortiss.tooling.kernel.model.INamedCommentedElement in this element. Includes the element for which this metric is recorded. Never exceeds NUMBER_OF_TOTAL_ELEMENTS.</td> </tr> <tr> - <td>10</td> - <td>HierarchicElementProvider</td> - <td>org.fortiss.tooling.ext.quality.HierarchicElementProvider</td> + <td>HierarchicElementMetricProvider</td> + <td>org.fortiss.tooling.ext.quality.HierarchicElementMetricProvider</td> <td>NUMBER_OF_TOTAL_COMMENTED_ELEMENTS</td> <td>Integer</td> <td>Total number of elements which are commentable and do not have null or an empty string as a comment.</td> </tr> <tr> - <td>11</td> - <td>HierarchicElementProvider</td> - <td>org.fortiss.tooling.ext.quality.HierarchicElementProvider</td> + <td>HierarchicElementMetricProvider</td> + <td>org.fortiss.tooling.ext.quality.HierarchicElementMetricProvider</td> <td>NUMBER_OF_TOTAL_LEAF_ELEMENTS</td> <td>Integer</td> <td>Total number of elements contained in this element which do not contain elements. Includes self.</td> </tr> <tr> - <td>12</td> <td>GraphMetricsProvider</td> <td>org.fortiss.tooling.ext.quality.GraphMetricsProvider</td> <td>BETWEENESS_CENTRALITY</td> @@ -121,7 +108,6 @@ <td>Value of the betweenness centrality of this element embedded in a graph of consisting of all elements which are contained in the element which contains this element, as well as all neighbors of these elements.</td> </tr> <tr> - <td>13</td> <td>GraphMetricsProvider</td> <td>org.fortiss.tooling.ext.quality.GraphMetricsProvider</td> <td>BETWEENESS_CENTRALITY_RECURSIVELY</td> @@ -129,7 +115,6 @@ <td>Same as above, but all connections are resolved to leaf elements, i.e. elements which do not contain other elements.</td> </tr> <tr> - <td>14</td> <td>GraphMetricsProvider</td> <td>org.fortiss.tooling.ext.quality.GraphMetricsProvider</td> <td>CLUSTERING_COEFFICIENT</td> @@ -137,87 +122,6 @@ <td>Clustering coefficient of this element. Ignores connection direction and resolves all neighbors to leaf elements.</td> </tr> <tr> - <td>15</td> - <td>ComponentMetricProvider</td> - <td>TODO (SB): Documentation of providers should be distributed to respective plugins. org.fortiss.af3.component.quality.ComponentMetricProvider</td> - <td>NUMBER_OF_TOTAL_CODE_CONSTANTS</td> - <td>Integer</td> - <td>Total number of constants in code specifications in this element and all contained elements.</td> - </tr> - <tr> - <td>16</td> - <td>ComponentMetricProvider</td> - <td>org.fortiss.af3.component.quality.ComponentMetricProvider</td> - <td>NUMBER_OF_TOTAL_CODE_CYCLOMATIC_COMPLEXITY</td> - <td>Integer</td> - <td>The total cyclomatic complexity of all code specifications in this element and all contained elements.</td> - </tr> - <tr> - <td>17</td> - <td>ComponentMetricProvider</td> - <td>org.fortiss.af3.component.quality.ComponentMetricProvider</td> - <td>NUMBER_OF_TOTAL_CODE_LINES</td> - <td>Integer</td> - <td>Total number of lines of code in all code specifications in this element and all contained elements.</td> - </tr> - <tr> - <td>18</td> - <td>ComponentMetricProvider</td> - <td>org.fortiss.af3.component.quality.ComponentMetricProvider</td> - <td>NUMBER_OF_TOTAL_CODE_COMMENTS</td> - <td>Integer</td> - <td>Total number of comment blocks in all code specifications in this element and all contained elements.</td> - </tr> - <tr> - <td>19</td> - <td>DataDictonaryProvider</td> - <td>org.fortiss.af3.component.quality.DataDictonaryProvider</td> - <td>-</td> - <td>-</td> - <td>Provides Metrics also collected by the HierarchicElementProvider, but for the DataDictionary.</td> - </tr> - <tr> - <td>20</td> - <td>SafetyMetricProvider</td> - <td>org.fortiss.af3.safety.quality.SafetyMetricProvider</td> - <td>SAFETY_LEVEL</td> - <td>String</td> - <td>String representation of the assigned safety level of this element.</td> - </tr> - <tr> - <td>21</td> - <td>SafetyMetricProvider</td> - <td>org.fortiss.af3.safety.quality.SafetyMetricProvider</td> - <td>SAFETY_LEVEL</td> - <td>String</td> - <td>String representation of the assigned safety level of this element.</td> - </tr> - <tr> - <td>22</td> - <td>SafetyMetricProvider</td> - <td>org.fortiss.af3.safety.quality.SafetyMetricProvider</td> - <td>SAFETY_LEVEL</td> - <td>String</td> - <td>String representation of the assigned safety level of this element.</td> - </tr> - <tr> - <td>23</td> - <td>AllocationTableProvider</td> - <td>org.fortiss.af3.task.quality.AllocationTableProvider</td> - <td>TASK_ALLOCATED_COMPONENTS</td> - <td>Integer</td> - <td>Number of allocated Components on this Task. This metric can only be non-null for org.fortiss.af3.task.model.Task Elements.</td> - </tr> - <tr> - <td>24</td> - <td>AllocationTableProvider</td> - <td>org.fortiss.af3.task.quality.AllocationTableProvider</td> - <td>HARDWARE_ALLOCATED_TASKS</td> - <td>Integer</td> - <td>Number of allocated Tasks on this ExecutionUnit. This metric can only be non-null for org.fortiss.af3.platform.model.ExecutionUnit Elements.</td> - </tr> - <tr> - <td>25</td> <td>ModelQualityService</td> <td>org.fortiss.tooling.ext.quality.service.ModelQualityService</td> <td>NESTING_LEVEL</td> @@ -225,7 +129,6 @@ <td>The depth of this element. Defined by the number of elements which have to be traversed to reach this element from the root.</td> </tr> <tr> - <td>26</td> <td>ModelQualityService</td> <td>org.fortiss.tooling.ext.quality.service.ModelQualityService</td> <td>CONSTRAINT_VIOLATIONS_ERROR</td> @@ -233,7 +136,6 @@ <td>Number of constraint violations of the severity error which have this element as source.</td> </tr> <tr> - <td>27</td> <td>ModelQualityService</td> <td>org.fortiss.tooling.ext.quality.service.ModelQualityService</td> <td>CONSTRAINT_VIOLATIONS_WARNING</td> diff --git a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/.ratings b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/.ratings index a0dfdcdd32991599396186c0c2bc9523ef06bc69..f93b691d3fecf7d59645f8367df3e13b0c4d58b3 100644 --- a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/.ratings +++ b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/.ratings @@ -1,5 +1,5 @@ -AF3QualityActivator.java 9f2f29b8d55c033e1df16320b0b8a1b6f0446f60 RED -GraphMetricsProvider.java 0d760fe19417a080016ebc4bfcc4c2753bde1e59 RED -HierarchicElementProvider.java cbe405204b08931fd5d219570d0ffb2ab49f27b7 RED +GraphMetricsProvider.java d18cff37dcb103a447cead64e1c2b00866996b3c YELLOW +HierarchicElementMetricProvider.java e76e846d76c6ba8782a20d9c9f9c6d57eaaa416e YELLOW IMetricProvider.java 99fc8993b0e65b2f8757978eeb0481d912f5608c GREEN IMetricUpdateListener.java c24dc7c0f282623bbf1eefac1fbbb6752c97ddf0 GREEN +ModelQualityActivator.java 6d5f0794aa48670cf45fb405bd7641bce6c1fec4 YELLOW diff --git a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/GraphMetricsProvider.java b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/GraphMetricsProvider.java index 0d760fe19417a080016ebc4bfcc4c2753bde1e59..d18cff37dcb103a447cead64e1c2b00866996b3c 100644 --- a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/GraphMetricsProvider.java +++ b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/GraphMetricsProvider.java @@ -25,15 +25,16 @@ import java.util.Queue; import java.util.Set; import java.util.Stack; +import static org.fortiss.tooling.kernel.utils.EcoreUtils.pickInstanceOf; + 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.IConnection; import org.fortiss.tooling.base.model.element.IConnector; import org.fortiss.tooling.base.model.element.IHierarchicElement; -import org.fortiss.tooling.ext.quality.data.MetricDataManager; +import org.fortiss.tooling.ext.quality.data.MetricData; import org.fortiss.tooling.ext.quality.data.MetricKey; -import org.fortiss.tooling.kernel.utils.EcoreUtils; /** * Supplies methods to compute certain graph metrics. @@ -41,9 +42,7 @@ import org.fortiss.tooling.kernel.utils.EcoreUtils; * @author groh */ -// TODO (SB): shouldn't this implement the interface IMetricProvider? If it is not possible to -// factorize this now, but the suggestions makes sense, create a ticket and reference it here -// using TODO (#xyz): blah). Otherwise, consider renaming the class to avoid the confusion. +// TODO (#4332) Restructure GraphMetricsProvider in quality Plugin public class GraphMetricsProvider { /** @@ -68,17 +67,15 @@ public class GraphMetricsProvider { graphNodes.addAll(scopeElement.getContainedElements()); } - // TODO (SB): Static import // Collect all elements to which currentElement has a outgoing connection - for(ExitConnectorBase exitConnector : EcoreUtils.pickInstanceOf(ExitConnectorBase.class, + for(ExitConnectorBase exitConnector : pickInstanceOf(ExitConnectorBase.class, scopeElement.getConnectors())) { for(IConnection exitConnection : exitConnector.getOutgoing()) { graphNodes.add(exitConnection.getTarget().getOwner()); } } - // TODO (SB): Static import // Collect all elements to which currentElement has a incoming connection - for(EntryConnectorBase entryConnector : EcoreUtils.pickInstanceOf(EntryConnectorBase.class, + for(EntryConnectorBase entryConnector : pickInstanceOf(EntryConnectorBase.class, scopeElement.getConnectors())) { for(IConnection entryConnection : entryConnector.getIncoming()) { graphNodes.add(entryConnection.getSource().getOwner()); @@ -161,24 +158,22 @@ public class GraphMetricsProvider { private static Set<IHierarchicElement> getUndirectedNeighbors(IHierarchicElement element) { Set<IHierarchicElement> neighbors = new HashSet<>(); - // TODO (SB): Static import - for(ExitConnectorBase exitConnectors : EcoreUtils.pickInstanceOf(ExitConnectorBase.class, + for(ExitConnectorBase exitConnectors : pickInstanceOf(ExitConnectorBase.class, element.getConnectors())) { recursivlyFollowOutgoingConnection(exitConnectors, neighbors); } - // TODO (SB): Static import - for(EntryConnectorBase entryConnectors : EcoreUtils.pickInstanceOf(EntryConnectorBase.class, + for(EntryConnectorBase entryConnectors : pickInstanceOf(EntryConnectorBase.class, element.getConnectors())) { recursivlyFollowIncomingConnection(entryConnectors, neighbors); } return neighbors; } - // TODO (SB): Pleae provide a link (DOI to paper, Wikipedia, ...) to a definition of the - // clustering coefficient? The algorithm is not obvious... /** * Calculates the clustering coefficient based on the neighborhood. - * + * https://en.wikipedia.org/wiki/Clustering_coefficient + * Clustering coefficient C for a node V is counting the triangles divided by the "number of neighbors of + * V" times "number of neighbors of V - 1" which results in the potential number of maximum links between the nodes * @param element * of which the coefficient shall be calculated * @return value of the coefficient @@ -186,19 +181,15 @@ public class GraphMetricsProvider { public static double calculateClusteringCoefficent(IHierarchicElement element) { Set<IHierarchicElement> neighbors = getUndirectedNeighbors(element); - int totalEdges = neighbors.size(); if(totalEdges < 2) { return 0.0; // If there are fewer than 2 neighbors, the coefficient is undefined (or 0). } - // Iterate over neighbors and get their neighbors and check if they are also our neighbor in // which case we have a triangle int triangles = 0; for(IHierarchicElement neighbor : neighbors) { - Set<IHierarchicElement> neighborNeighbors = getUndirectedNeighbors(neighbor); - for(IHierarchicElement secondNeighbor : neighbors) { if(secondNeighbor != neighbor && neighborNeighbors.contains(secondNeighbor)) { triangles++; @@ -209,92 +200,90 @@ public class GraphMetricsProvider { return clusteringCoefficient; } - // TODO (SB): Please provide a link (DOI to paper, Wikipedia, ...) to a definition of the - // betweenness centrality. The algorithm is not obvious... /** * Calculates and saves the betweenness centrality of all elements contained inside the provided - * scopeElement. + * scopeElement. Described for example in https://en.wikipedia.org/wiki/Betweenness_centrality * * @param scopeElement * the scope of this calculation - * @param manager + * @param metricData * location to save the metrics * @param recursively * if true, all calculation will be carried out on leaf elements - * TODO (SB):, otherwise.... <not obvious :-) > + * if false, it is only computing the centrality with the children + * which means the inner circle. */ public static void calculateBetweennessCentrality(IHierarchicElement scopeElement, - MetricDataManager manager, boolean recursively) { + MetricData metricData, boolean recursively) { - // TODO (SB): Use inverse logic and return to decrease nesting depth - // if (foo) { return; } bar(); // Abort if no elements are found - if(!scopeElement.getContainedElements().isEmpty()) { + if(scopeElement.getContainedElements().isEmpty()) { + return; + } + + Set<IHierarchicElement> graphNodes = getLocalGraphView(scopeElement, recursively); + // Initialize the betweenness values for all nodes to zero + Map<IHierarchicElement, Double> betweenness = new HashMap<>(); + for(IHierarchicElement elementNode : graphNodes) { + betweenness.put(elementNode, 0.0); + } - Set<IHierarchicElement> graphNodes = getLocalGraphView(scopeElement, recursively); - // Initialize the betweenness values for all nodes to zero - Map<IHierarchicElement, Double> betweenness = new HashMap<>(); - for(IHierarchicElement elementNode : graphNodes) { - betweenness.put(elementNode, 0.0); - } + // Iterate over all collected nodes + for(IHierarchicElement elementNode : graphNodes) { - // Iterate over all collected nodes - for(IHierarchicElement elementNode : graphNodes) { + // Initialize all variables with standard values + Stack<IHierarchicElement> stack = new Stack<>(); + Map<IHierarchicElement, List<IHierarchicElement>> predecessors = new HashMap<>(); + Map<IHierarchicElement, Integer> distance = new HashMap<>(); + Map<IHierarchicElement, Double> dependency = new HashMap<>(); + Queue<IHierarchicElement> queue = new LinkedList<>(); - // Initialize all variables - Stack<IHierarchicElement> stack = new Stack<>(); - Map<IHierarchicElement, List<IHierarchicElement>> predecessors = new HashMap<>(); - Map<IHierarchicElement, Integer> distance = new HashMap<>(); - Map<IHierarchicElement, Double> dependency = new HashMap<>(); - Queue<IHierarchicElement> queue = new LinkedList<>(); + for(IHierarchicElement v : graphNodes) { + predecessors.put(v, new ArrayList<>()); + distance.put(v, -1); + dependency.put(v, 0.0); + } + dependency.put(elementNode, 1.0); + distance.put(elementNode, 0); + queue.add(elementNode); - for(IHierarchicElement v : graphNodes) { - predecessors.put(v, new ArrayList<>()); - distance.put(v, -1); - dependency.put(v, 0.0); - } - dependency.put(elementNode, 1.0); - distance.put(elementNode, 0); - queue.add(elementNode); + processCentrality(queue, stack, predecessors, distance, dependency, graphNodes, + elementNode, recursively); - processCentrality(queue, stack, predecessors, distance, dependency, graphNodes, - elementNode, recursively); + // Initialize delta + Map<IHierarchicElement, Double> delta = new HashMap<>(); + for(IHierarchicElement v : graphNodes) { + delta.put(v, 0.0); + } - // Initialize delta - Map<IHierarchicElement, Double> delta = new HashMap<>(); - for(IHierarchicElement v : graphNodes) { - delta.put(v, 0.0); + while(!stack.isEmpty()) { + IHierarchicElement w = stack.pop(); + for(IHierarchicElement v : predecessors.get(w)) { + double c = (dependency.get(v) / dependency.get(w)) * (1.0 + delta.get(w)); + delta.put(v, delta.get(v) + c); } - - while(!stack.isEmpty()) { - IHierarchicElement w = stack.pop(); - for(IHierarchicElement v : predecessors.get(w)) { - double c = (dependency.get(v) / dependency.get(w)) * (1.0 + delta.get(w)); - delta.put(v, delta.get(v) + c); - } - if(!w.equals(elementNode)) { - betweenness.put(w, betweenness.get(w) + delta.get(w)); - } + if(!w.equals(elementNode)) { + betweenness.put(w, betweenness.get(w) + delta.get(w)); } } - // Save metric - saveMetric(scopeElement, manager, recursively, betweenness); } + // Save metric + saveMetric(scopeElement, metricData, recursively, betweenness); } /** Saving the metrics for each contained element of an {@link IHierarchicElement}. */ - private static void saveMetric(IHierarchicElement scopeElement, MetricDataManager manager, + private static void saveMetric(IHierarchicElement scopeElement, MetricData metricData, boolean recursively, Map<IHierarchicElement, Double> betweenness) { MetricKey key = recursively ? MetricKey.BETWEENESS_CENTRALITY_RECURSIVELY : MetricKey.BETWEENESS_CENTRALITY; for(IHierarchicElement child : scopeElement.getContainedElements()) { - manager.getTreeNodeLookupTable().get(child).getStoredDoubles().put(key, + metricData.getTreeNodeLookupTable().get(child).getStoredDoubles().put(key, betweenness.get(child)); } } /** - * Performs intermediate calculations for the betweenness centrality algorithm + * Performs intermediate calculations for the betweenness centrality algorithm. * * @param queue * of nodes for Breadth-First Search. @@ -327,8 +316,7 @@ public class GraphMetricsProvider { stack.push(v); // Iterate over all connectors going out from the element - for(ExitConnectorBase exitConnectors : EcoreUtils - .pickInstanceOf(ExitConnectorBase.class, v.getConnectors())) { + for(ExitConnectorBase exitConnectors : pickInstanceOf(ExitConnectorBase.class, v.getConnectors())) { // Iterate over all connections for(IConnection outgoingConnection : exitConnectors.getOutgoing()) { @@ -359,16 +347,13 @@ public class GraphMetricsProvider { // Check if element is in node list, to avoid creating data for // nodes outside of our graph if(graphNodes.contains(targetElement)) { - // TODO (SB): Introduce local variables with good names for - // distance.get(targetElement) and distance.get(v) - if(distance.get(targetElement) < 0) { + var targetDistance = distance.get(targetElement); + var vDistance = distance.get(v); + // first start of distance calculation from v to the target Element + if(targetDistance < 0) { queue.add(targetElement); - distance.put(targetElement, distance.get(v) + 1); - } - // TODO (SB): Just for safety-checking: Is it intended, there there is - // no "else", i.e. that both conditions could be true and both branches - // should be entered? - if(distance.get(targetElement) == distance.get(v) + 1) { + distance.put(targetElement, vDistance + 1); + }else if(targetDistance == vDistance + 1) { dependency.put(targetElement, dependency.get(targetElement) + dependency.get(v)); predecessor.get(targetElement).add(v); 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/HierarchicElementMetricProvider.java similarity index 54% rename from org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/HierarchicElementProvider.java rename to org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/HierarchicElementMetricProvider.java index cbe405204b08931fd5d219570d0ffb2ab49f27b7..e76e846d76c6ba8782a20d9c9f9c6d57eaaa416e 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/HierarchicElementMetricProvider.java @@ -15,74 +15,79 @@ +--------------------------------------------------------------------------*/ package org.fortiss.tooling.ext.quality; +import static org.fortiss.tooling.kernel.utils.EcoreUtils.pickInstanceOf; + 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.MetricKey; import org.fortiss.tooling.ext.quality.data.MetricTreeNode; import org.fortiss.tooling.kernel.model.IIdLabeled; import org.fortiss.tooling.kernel.model.INamedCommentedElement; -import org.fortiss.tooling.kernel.utils.EcoreUtils; /** * {@link IMetricProvider} to collect various metrics from an {@link IHierarchicElement}. * * @author groh */ -// TODO (SB): Rename to HierarchicElementMetricProvider -public class HierarchicElementProvider implements IMetricProvider<IHierarchicElement> { +public class HierarchicElementMetricProvider implements IMetricProvider<IHierarchicElement> { /** {@inheritDoc} */ @Override public void collectMetrics(MetricTreeNode node, IHierarchicElement currentElement) { - // TODO (SB): Use better variable name, e.g. intMetrics. See also comment in MetricTreeNode - var integers = node.getStoredIntegers(); + var intMetrics = node.getStoredIntegers(); // Only collect these metrics if the name is null, in which case they have not been // collected before // This is used in some cases to combine metrics from two different IHierarchicElement if(node.getName() == null) { // Metrics are always set to default value, as these metric are combined later - // TODO (SB): The ternary operators here very hard to read, and later on you use an if - // anyways. - // Suggestion: if (currentElement instanceof INamedCommentedElement) { bla} else { - // blub}. - boolean isElementCommentable = currentElement instanceof INamedCommentedElement; - integers.put(MetricKey.NUMBER_OF_TOTAL_COMMENTABLE_ELEMENTS, - isElementCommentable ? 1 : 0); - String comment = isElementCommentable - ? ((INamedCommentedElement)currentElement).getComment() : null; - integers.put(MetricKey.NUMBER_OF_TOTAL_COMMENTED_ELEMENTS, - comment != null && comment != "" ? 1 : 0); - if(isElementCommentable) { + String comment; + if(currentElement instanceof INamedCommentedElement) { + intMetrics.put(MetricKey.NUMBER_OF_TOTAL_COMMENTABLE_ELEMENTS, 1); + comment =((INamedCommentedElement)currentElement).getComment(); + if(comment != "") { + intMetrics.put(MetricKey.NUMBER_OF_TOTAL_COMMENTED_ELEMENTS, 1); + } node.setName(((INamedCommentedElement)currentElement).getName()); - } else { - node.setName("Unnamable Element"); + }else { + intMetrics.put(MetricKey.NUMBER_OF_TOTAL_COMMENTABLE_ELEMENTS, 0); + comment = null; + intMetrics.put(MetricKey.NUMBER_OF_TOTAL_COMMENTED_ELEMENTS, 0); + node.setName("No Name existant"); } - - integers.put(MetricKey.UNIQUE_ID, (currentElement instanceof IIdLabeled) - ? ((IIdLabeled)currentElement).getId() : -1); + + if(currentElement instanceof IIdLabeled) { + intMetrics.put(MetricKey.UNIQUE_ID,((IIdLabeled)currentElement).getId()); + }else { + intMetrics.put(MetricKey.UNIQUE_ID, -1); + } } + // connector metrics var connectors = currentElement.getConnectors(); - integers.put(MetricKey.NUMBER_OF_CONNECTORS, connectors.size()); - - integers.put(MetricKey.NUMBER_OF_CONTAINED_ELEMENTS, + intMetrics.put(MetricKey.NUMBER_OF_CONNECTORS, connectors.size()); + intMetrics.put(MetricKey.NUMBER_OF_CONTAINED_ELEMENTS, currentElement.getContainedElements().size()); - integers.put(MetricKey.NUMBER_OF_CONNECTIONS, currentElement.getConnections().size()); - + intMetrics.put(MetricKey.NUMBER_OF_CONNECTIONS, currentElement.getConnections().size()); + // depth metrics - integers.put(MetricKey.NUMBER_OF_TOTAL_CONNECTORS, connectors.size()); - // TODO (SB): Static import (CTRL+SHIFT+M). (2x) - var entry_connectors = EcoreUtils.pickInstanceOf(EntryConnectorBase.class, connectors); - var exit_connectors = EcoreUtils.pickInstanceOf(ExitConnectorBase.class, connectors); - integers.put(MetricKey.NUMBER_OF_TOTAL_ENTRY_CONNECTORS, entry_connectors.size()); - integers.put(MetricKey.NUMBER_OF_TOTAL_EXIT_CONNECTORS, exit_connectors.size()); + intMetrics.put(MetricKey.NUMBER_OF_TOTAL_CONNECTORS, connectors.size()); + + var entry_connectors = pickInstanceOf(EntryConnectorBase.class, connectors); + var exit_connectors = pickInstanceOf(ExitConnectorBase.class, connectors); + intMetrics.put(MetricKey.NUMBER_OF_TOTAL_ENTRY_CONNECTORS, entry_connectors.size()); + intMetrics.put(MetricKey.NUMBER_OF_TOTAL_EXIT_CONNECTORS, exit_connectors.size()); + + intMetrics.put(MetricKey.NUMBER_OF_TOTAL_ELEMENTS, 1); - integers.put(MetricKey.NUMBER_OF_TOTAL_ELEMENTS, 1); + if (currentElement.getContainedElements().isEmpty()) { + intMetrics.put(MetricKey.NUMBER_OF_TOTAL_LEAF_ELEMENTS, 0); + }else { + intMetrics.put(MetricKey.NUMBER_OF_TOTAL_LEAF_ELEMENTS, 1); + } - // TODO (SB): size() == 0 --> isEmpty() - integers.put(MetricKey.NUMBER_OF_TOTAL_LEAF_ELEMENTS, - currentElement.getContainedElements().size() == 0 ? 1 : 0); - } + //graph metrics + } } 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/ModelQualityActivator.java similarity index 75% rename from org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/AF3QualityActivator.java rename to org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/ModelQualityActivator.java index 9f2f29b8d55c033e1df16320b0b8a1b6f0446f60..6d5f0794aa48670cf45fb405bd7641bce6c1fec4 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/ModelQualityActivator.java @@ -19,21 +19,19 @@ package org.fortiss.tooling.ext.quality; import org.eclipse.core.runtime.Plugin; import org.fortiss.tooling.base.model.element.IHierarchicElement; import org.fortiss.tooling.ext.quality.service.IModelQualityService; -import org.fortiss.tooling.ext.quality.service.ModelQualityService; import org.osgi.framework.BundleContext; -// TODO (SB): Rename class to QualityActivator or ModelQualityActivator. This is the kernel, not AF3 /** * The activator class controls the plug-in life cycle. * * @author blaschke */ -public class AF3QualityActivator extends Plugin { +public class ModelQualityActivator extends Plugin { /** The plug-in ID. */ - public static final String PLUGIN_ID = AF3QualityActivator.class.getPackage().getName(); // $NON-NLS-1$ + public static final String PLUGIN_ID = ModelQualityActivator.class.getPackage().getName(); // $NON-NLS-1$ /** The shared instance. */ - private static AF3QualityActivator plugin; + private static ModelQualityActivator plugin; /** {@inheritDoc} */ @Override @@ -41,10 +39,9 @@ public class AF3QualityActivator extends Plugin { super.start(context); plugin = this; System.out.println("[Plugin] " + PLUGIN_ID + " started."); - - // TODO: Use only IModelQualityService. Store it in a variable with a brief name, e.g., mqs - ModelQualityService.getInstance().startService(); - IModelQualityService.getInstance().registerMetricProvider(new HierarchicElementProvider(), + IModelQualityService mqs = IModelQualityService.getInstance(); + mqs.startService(); + mqs.registerMetricProvider(new HierarchicElementMetricProvider(), IHierarchicElement.class); } @@ -56,7 +53,7 @@ public class AF3QualityActivator extends Plugin { } /** Returns the shared instance. */ - public static AF3QualityActivator getDefault() { + public static ModelQualityActivator getDefault() { return plugin; } } diff --git a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/.ratings b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/.ratings index fbdbd5aef728a4bbee5b090d775833b6a9b950ac..03a1517ed3dced674da0199a5d2f966e0f2e248e 100644 --- a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/.ratings +++ b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/.ratings @@ -1,4 +1,4 @@ -DataRootElement.java ab41ea9b52b095be3c03a85a6d1a3036b3026062 RED -MetricDataManager.java dd2a265e4ac2738b5b68048111597902a763d79f RED -MetricKey.java ac73424d340e52df84d6ad202d43d0cef9aeba78 RED -MetricTreeNode.java 0e289fb25da429e11a931dec23d34204d7f12dd2 RED +DataRootElement.java e598763b5199c4810da191623a07a9edeb154a84 YELLOW +MetricData.java 03fd1cf0477a42f1f50c899c180035498d21faa3 YELLOW +MetricKey.java 81ba35f8537c4cb9c0f487a2bfafdb65f9d6c3c0 YELLOW +MetricTreeNode.java 8eb3c6761a3af482215d48e1bada53415d4ba8e4 YELLOW diff --git a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/DataRootElement.java b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/DataRootElement.java index ab41ea9b52b095be3c03a85a6d1a3036b3026062..e598763b5199c4810da191623a07a9edeb154a84 100644 --- a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/DataRootElement.java +++ b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/DataRootElement.java @@ -27,8 +27,7 @@ import org.fortiss.tooling.kernel.extension.data.ITopLevelElement; * @author groh */ public class DataRootElement { - // TODO (SB): Comments start with a capital letter, end with a dot, and are free of typos. - /** the last time a metric tree was refreshed */ + /** The last time a metric tree was refreshed. */ private LocalDateTime lastRefresh; /** the last time the metric tree was refreshed */ @@ -37,16 +36,7 @@ public class DataRootElement { /** Root {@link MetricTreeNode} for the metric tree containg all data */ private MetricTreeNode rootNode; - /** - * Constructor: Creates a new instance of the {@link DataRootElement}. - * - * @param lastRefresh - * the last time the rootNode was refreshed - * @param topLevelElement - * the {@link ITopLevelElement} of the project - * @param rootNode - * the root node of the metric data tree - */ + /**Constructor. */ public DataRootElement(LocalDateTime lastRefresh, ITopLevelElement topLevelElement, MetricTreeNode rootNode) { super(); @@ -55,34 +45,32 @@ public class DataRootElement { this.rootNode = rootNode; } - /** Returns {@link #lastRefresh}. */ + /** Getter for {@link #lastRefresh}. */ public LocalDateTime getLastRefresh() { return lastRefresh; } - // TODO (SB): Link the field as I showed you above (5x). If you add an "#" in front of the field - // name, auto-complete works. - /** Sets lastRefresh. */ + /** Setter for {@link #lastRefresh}. */ public void setLastRefresh(LocalDateTime lastRefresh) { this.lastRefresh = lastRefresh; } - /** Returns topLevelElement. */ + /** Getter for {@link #topLevelElement}. */ public ITopLevelElement getTopLevelElement() { return topLevelElement; } - /** Sets topLevelElement. */ + /** Setter for {@link #topLevelElement}. */ public void setTopLevelElement(ITopLevelElement topLevelElement) { this.topLevelElement = topLevelElement; } - /** Returns rootNode. */ + /** Getter for {@link #MetricTreeNode}. */ public MetricTreeNode getRootNode() { return rootNode; } - /** Sets rootNode. */ + /** Setter for {@link #MetricTreeNode}. */ public void setRootNode(MetricTreeNode metricTreeNode) { this.rootNode = metricTreeNode; } diff --git a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/MetricDataManager.java b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/MetricData.java similarity index 64% rename from org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/MetricDataManager.java rename to org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/MetricData.java index dd2a265e4ac2738b5b68048111597902a763d79f..03fd1cf0477a42f1f50c899c180035498d21faa3 100644 --- a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/MetricDataManager.java +++ b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/data/MetricData.java @@ -21,45 +21,31 @@ import java.util.Map; import org.eclipse.emf.ecore.EObject; import org.fortiss.tooling.kernel.model.IProjectRootElement; -// TODO (SB): Rename class name to something like "MetricData". It is not a manager, but a data container. -// TODO (SB): Remove af3 from the comment. We are in the kernel here! /** - * Class containing all computed metrics for the current af3 instance. + * Class storing the metrics computed for the all suitable elemnets. * * @author groh */ -public class MetricDataManager { +public class MetricData { - // TODO (SB): Comments start with a capital letter and end with a dot. - /** a map to lookup the corresponding tree node for any {@link EObject} */ + /** A map to lookup the corresponding tree node for any {@link EObject}. */ private Map<EObject, MetricTreeNode> treeNodeLookupTable; - /** a map to lookup the corresponding root tree node for a project */ + /** A map to lookup the corresponding root tree node for a project. */ private Map<IProjectRootElement, DataRootElement> dataRootElementMap; - // TODO (SB): Constructors are commented just with "Constructor." (one line). - /** - * Constructor: Creates a new instance of the MetricDataManager. - */ - public MetricDataManager() { + /** Constructor.*/ + public MetricData() { dataRootElementMap = new HashMap<>(); treeNodeLookupTable = new HashMap<>(); } - // TODO (SB): You can just use the following comment (avoids inconsistencies). /** Getter for {@link #treeNodeLookupTable}. */ - /** - * @return the lookup mapping between {@link EObject} and a {@link MetricTreeNode}. - */ public Map<EObject, MetricTreeNode> getTreeNodeLookupTable() { return treeNodeLookupTable; } - // TODO (SB): As above - /** - * @return the map between {@link IProjectRootElement} and the corresponding root - * {@link DataRootElement}. - */ + /** Getter for {@link #DataRootElementMap}. */ public Map<IProjectRootElement, DataRootElement> getDataRootElementMap() { return dataRootElementMap; } 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 index ac73424d340e52df84d6ad202d43d0cef9aeba78..81ba35f8537c4cb9c0f487a2bfafdb65f9d6c3c0 100644 --- 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 @@ -20,85 +20,68 @@ import java.util.List; /** * Enum class representing a key which can be used to store a respective metric. - * + * Metrics provided by the HierarchicElementProvider. * @author groh */ public enum MetricKey { - // - // Metrics provided by the HierarchicElementProvider - // TODO (SB): All comments should end with a dot. - // /** Unique ID of the element */ UNIQUE_ID(false), - /** Key for the metric counting ports */ + /** Key for the metric counting ports. */ NUMBER_OF_CONNECTORS(false), - /** Key for the metric counting elements */ + /** Key for the metric counting elements. */ NUMBER_OF_CONTAINED_ELEMENTS(false), - /** Key for the metric counting channels */ + /** Key for the metric counting channels. */ NUMBER_OF_CONNECTIONS(false), - // TODO (SB): This adds knowledge about the AF3 metamodel to the kernel. Create a ticket and a - // TODO(#xyz) for a cleaner solution. - /** Safety level of the element */ + // TODO (#4333): + /** Safety level of the element. */ SAFETY_LEVEL(false, true), - /** How deeply nested the corresponding element is */ + /** How deeply nested the corresponding element is. */ NESTING_LEVEL(false), - /** The betweenness centrality of the corresponding element */ + /** The betweenness centrality of the corresponding element. */ BETWEENESS_CENTRALITY(false, 0.0), /** * The betweenness centrality of the corresponding element considering other elements - * recursively + * recursively. */ BETWEENESS_CENTRALITY_RECURSIVELY(false, 0.0), /** The clustering coefficient of the element considering its neighbors. */ CLUSTERING_COEFFICIENT(false, 0.0), - /** How many constraints this element violates with severity error */ + /** How many constraints this element violates with severity error. */ CONSTRAINT_VIOLATIONS_ERROR(false), - /** How many constraints this element violates with severity warning */ + /** How many constraints this element violates with severity warning. */ CONSTRAINT_VIOLATIONS_WARNING(false), - - // TODO (SB): This adds knowledge about the AF3 metamodel to the kernel. Create a ticket and a - // TODO(#xyz) for a cleaner solution. (see above) - /** Number of allocated components to this task */ + // TODO(#4333) Remove knowledge about af3 from the kernel. + /** Number of allocated components to this task. */ TASK_ALLOCATED_COMPONENTS(false), - // TODO (SB): This adds knowledge about the AF3 metamodel to the kernel. Create a ticket and a - // TODO(#xyz) for a cleaner solution. (see above) - /** How many constraints this element violates with severity warning */ + // TODO (#4333): Remove knowledge about af3 from the kernel. + /** How many constraints this element violates with severity warning. */ EXECUTION_UNIT_ALLOCATED_TASKS(false), - // // Metrics which are collected over all children nodes - // - /** Key for the metric counting the total amount of ports contained */ + /** Key for the metric counting the total amount of ports contained. */ NUMBER_OF_TOTAL_CONNECTORS(true), - /** Key for the metric counting the total amount of input ports contained */ + /** Key for the metric counting the total amount of input ports contained. */ NUMBER_OF_TOTAL_ENTRY_CONNECTORS(true), - /** Key for the metric counting the total amount of output ports contained */ + /** Key for the metric counting the total amount of output ports contained. */ NUMBER_OF_TOTAL_EXIT_CONNECTORS(true), - /** Key for the metric counting the total amount of elements contained */ + /** Key for the metric counting the total amount of elements contained. */ NUMBER_OF_TOTAL_ELEMENTS(true), - /** Key for the metric counting the total amount of elements which can be commented */ + /** Key for the metric counting the total amount of elements which can be commented. */ NUMBER_OF_TOTAL_COMMENTABLE_ELEMENTS(true), - /** Key for the metric counting the total amount of elements which are commented */ + /** Key for the metric counting the total amount of elements which are commented. */ NUMBER_OF_TOTAL_COMMENTED_ELEMENTS(true), - /** - * Key for the metric counting the total amount of elements which do not contain other elements - */ + /** Key for the metric counting the total amount of elements which do not contain other elements. */ NUMBER_OF_TOTAL_LEAF_ELEMENTS(true), - /** - * Key for the metric counting of the total amount of constant values in all code specifications - */ + /** Key for the metric counting of the total amount of constant values in all code specifications. */ NUMBER_OF_TOTAL_CODE_CONSTANTS(true), - - /** Cyclomatic complexity number as sum over all components */ + /** Cyclomatic complexity number as sum over all components. */ NUMBER_OF_TOTAL_CODE_CYCLOMATIC_COMPLEXITY(true), - - /** Counts the Lines of Code (LoC) in the component and its sub-components */ + /** Counts the Lines of Code (LoC) in the component and its sub-components. */ NUMBER_OF_TOTAL_CODE_LINES(true), - - /** Representation of the total amount of comment blocks in all code specifications */ + /** Representation of the total amount of comment blocks in all code specifications. */ NUMBER_OF_TOTAL_CODE_COMMENTS(true); /** Metrics which are a combination from the data of multiple nodes */ @@ -106,7 +89,15 @@ public enum MetricKey { /** Getter for {@link #collectorKeys}. */ public static List<MetricKey> getCollectorKeys() { - return collectorKeys; + if (collectorKeys == null) { + collectorKeys = new ArrayList<>(); + for (MetricKey key : MetricKey.values()) { + if (key.isCollectorKey) { + collectorKeys.add(key); + } + } + } + return collectorKeys; } /** Used for populating the {@link MetricKey#getCollectorKeys()} method. */ @@ -116,6 +107,7 @@ public enum MetricKey { // only doubles and strings. What about marking the type of a MetricKey with a // Class<? extends Number> field? In the constructor, you can check that only the admissible // types Integer, Double, String are passed. + // TODO (#4333) /** Determines if the corresponding value to this key is a string or not */ private boolean isStringValue; /** Determines if the corresponding value to this key is a integer or not */ @@ -179,14 +171,8 @@ public enum MetricKey { return isDoubleValue; } - // TODO (SB): It would be less bloat and easier to read to do a lazy initialization of - // collectorKeys in getCollectorKeys(). I.e., do not initialize field with empty list, but - // do a null check and set collectorKeys when not already done. + /** Get all collector keys. */ static { - for(MetricKey key : MetricKey.values()) { - if(key.isCollectorKey) { - collectorKeys.add(key); - } - } + collectorKeys = getCollectorKeys(); } } 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 0e289fb25da429e11a931dec23d34204d7f12dd2..8eb3c6761a3af482215d48e1bada53415d4ba8e4 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 @@ -33,15 +33,14 @@ public class MetricTreeNode { /** stores the children of this tree node */ private List<MetricTreeNode> children; - // TODO (SB): Rename to integerMetrics (also getter). Same for doubles and strings /** Map containing all metrics which are a Integer */ - private Map<MetricKey, Integer> storedIntegers; + private Map<MetricKey, Integer> integerMetrics; /** Map containing all metrics which are a Double */ - private Map<MetricKey, Double> storedDoubles; + private Map<MetricKey, Double> doubleMetrics; /** Map containing all metrics which are a String */ - private Map<MetricKey, String> storedStrings; + private Map<MetricKey, String> stringMetrics; /** name of the element which is associated with this data */ private String name; @@ -49,41 +48,39 @@ public class MetricTreeNode { /** Constructor. */ public MetricTreeNode() { children = new ArrayList<>(); - storedIntegers = new HashMap<>(); - storedDoubles = new HashMap<>(); - storedStrings = new HashMap<>(); + integerMetrics = new HashMap<>(); + doubleMetrics = new HashMap<>(); + stringMetrics = new HashMap<>(); } - /** @return the children of this node */ + /** Getter for {@link #children}. */ public List<MetricTreeNode> getChildren() { return children; } - /** @return the name of the element which is associated with this data */ + /** Getter for {@link #name}. */ public String getName() { return name; } - /** Set the name of this node. */ + /** Setter for {@link #name}. */ public void setName(String name) { this.name = name; } - // TODO (SB): In addition to renaming (see above), adjust comment: "the {@link Integer} metric - // map". (Hint: auto-completing types also works in comments). - /** @return the stored Integer map */ + /** Getter for {@link #integerMetrics}. */ public Map<MetricKey, Integer> getStoredIntegers() { - return storedIntegers; + return integerMetrics; } - /** @return the stored Doubles map */ + /** Getter for {@link #doubleMetrics}. */ public Map<MetricKey, Double> getStoredDoubles() { - return storedDoubles; + return doubleMetrics; } - /** @return the stored Strings map */ + /** Getter for {@link #stringMetrics}. */ public Map<MetricKey, String> getStoredStrings() { - return storedStrings; + return stringMetrics; } /** @@ -97,9 +94,9 @@ public class MetricTreeNode { */ public Double getValueAsDouble(MetricKey key) { if(key.isDoubleValue()) { - return storedDoubles.get(key); + return doubleMetrics.get(key); } - Integer val = storedIntegers.get(key); + Integer val = integerMetrics.get(key); return val == null ? null : val.doubleValue(); } diff --git a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/service/.ratings b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/service/.ratings index d882fa6e7e863cdaa40a5d822ab2a92e87469991..4f07e9c17b2c7f4892588fd96407588e18f26831 100644 --- a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/service/.ratings +++ b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/service/.ratings @@ -1,2 +1,2 @@ -IModelQualityService.java 9a844024d62c79421e39d38699333587bec187d7 GREEN -ModelQualityService.java 7d0021f1cd1281fa599f615b425bc9fd4e372f91 RED +IModelQualityService.java e474e51bec8ce03209b69a40f3433a070bd73daa YELLOW +ModelQualityService.java 4a620f5c7732069d78b0e37e051ff99f4732642e YELLOW 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 9a844024d62c79421e39d38699333587bec187d7..e474e51bec8ce03209b69a40f3433a070bd73daa 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 @@ -18,6 +18,8 @@ package org.fortiss.tooling.ext.quality.service; import org.eclipse.emf.ecore.EObject; import org.fortiss.tooling.ext.quality.IMetricProvider; import org.fortiss.tooling.ext.quality.IMetricUpdateListener; +import org.fortiss.tooling.ext.quality.data.MetricData; +import org.fortiss.tooling.ext.quality.storage.ModelQualityStorageManager; import org.fortiss.tooling.kernel.extension.data.ITopLevelElement; /** @@ -30,6 +32,9 @@ public interface IModelQualityService { static IModelQualityService getInstance() { return ModelQualityService.getInstance(); } + + /** Starting the service. */ + void startService(); /** Registers the metric provider with the service. */ <T extends EObject> void registerMetricProvider(IMetricProvider<T> provider, @@ -38,6 +43,9 @@ public interface IModelQualityService { /** Schedules an analysis of the metrics and processes them. */ void scheduleMetricCollection(ITopLevelElement top); + /** Returns the {@link MetricData} for the Service. */ + MetricData getMetricData(); + /** * Registers the provided {@link IMetricUpdateListener} to be called when the metrics are * updated. @@ -46,4 +54,12 @@ public interface IModelQualityService { * to be registered */ void registerMetricUpdateListener(IMetricUpdateListener listener); + + /** Creating the quality folder to store the metrics in. */ + static void createQualityFolder() { + if(!ModelQualityStorageManager.MODEL_QUALITY_PROJECT_DIR.exists()) { + ModelQualityStorageManager.MODEL_QUALITY_PROJECT_DIR.mkdirs(); + } + } + } 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 7d0021f1cd1281fa599f615b425bc9fd4e372f91..4a620f5c7732069d78b0e37e051ff99f4732642e 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 @@ -31,6 +31,7 @@ import java.util.Optional; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; @@ -42,7 +43,7 @@ import org.fortiss.tooling.ext.quality.GraphMetricsProvider; import org.fortiss.tooling.ext.quality.IMetricProvider; import org.fortiss.tooling.ext.quality.IMetricUpdateListener; import org.fortiss.tooling.ext.quality.data.DataRootElement; -import org.fortiss.tooling.ext.quality.data.MetricDataManager; +import org.fortiss.tooling.ext.quality.data.MetricData; import org.fortiss.tooling.ext.quality.data.MetricKey; import org.fortiss.tooling.ext.quality.data.MetricTreeNode; import org.fortiss.tooling.ext.quality.storage.CSVFileWriter; @@ -66,35 +67,19 @@ import org.fortiss.tooling.kernel.utils.EcoreUtils; * @author blaschke * @author groh */ -// TODO (SB): Change public to /* package */ to ensure use of IModelQualityService interface -public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider<? extends EObject>> +/* package */ class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider<? extends EObject>> implements IIntrospectiveKernelService, IModelQualityService, IPersistencyServiceListener { /** The singleton instance. */ private static final ModelQualityService INSTANCE = new ModelQualityService(); /** Returns singleton instance of the service. */ - // TODO (SB): Change public to /* package */ to ensure use of IModelQualityService interface - public static ModelQualityService getInstance() { + /* package */ static ModelQualityService getInstance() { return INSTANCE; } - // TODO (SB): This service does not use the Eclipse extension points. Remove these 3 constants - // and have the respective methods return "null" - /** The connector extension point ID. */ - private static final String EXTENSION_POINT_NAME = - "org.fortiss.tooling.ext.quality.metricService"; - - /** The connector configuration element name. */ - private static final String CONFIGURATION_ELEMENT_NAME = "metricService"; - - /** The connector attribute name. */ - private static final String ATTRIBUTE_NAME = "metricService"; - - // TODO (SB): Rename class name, this field, getter, etc. to something like "MetricData". It is - // not a manager, but a data container /** Instance of the MetricDataManager. */ - private MetricDataManager metricDataManagerInstance = new MetricDataManager(); + private MetricData metricDataContainer = new MetricData(); /** List of {@link IMetricUpdateListener} which are called when the metrics are updated */ private List<IMetricUpdateListener> metricUpdateListeners = new ArrayList<>(); @@ -108,9 +93,6 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider @Override protected IStatus run(IProgressMonitor monitor) { - // TODO (SB): Please check if the following comment that explains the loop logic is - // correct (otherwise consider changing to while (!queuedProcessableElements.isEmpty()) - // // Using a do-while-true loop with internal termination in order to ensure that the // monitor is checked for cancellation at least once. do { @@ -127,6 +109,8 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider e.printStackTrace(); } catch(IOException e) { e.printStackTrace(); + } catch (CoreException e) { + e.printStackTrace(); } } while(true); } @@ -136,7 +120,6 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider @Override public void scheduleMetricCollection(ITopLevelElement element) { queuedProcessableElements.add(element); - // TODO (SB): Please check if the following comment is correct // The Eclipse Job ensures that at most one instance of the metrics collection is executed. // When a new element is added to the processing queue while a job is active, this current // job will run longer in order to process it. @@ -170,7 +153,7 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider "\n\nThis service allows to track the evolution of model metrics." + "\n The service determines the current metrics of a model and stores" + "\n them in a CSV file for later analysis of the modeling history." + - "\n\nThe service extension point is '" + EXTENSION_POINT_NAME + "'."; + "\n\nThe service extension point is 'not existant'."; } /** @@ -180,10 +163,11 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider * the {@link ITopLevelElement} on which the analysis should be performed * @throws IOException * @throws NoSuchAlgorithmException + * @throws CoreException */ private void performMetricCollection(ITopLevelElement topLevelElement) - throws NoSuchAlgorithmException, IOException { - // TODO (SB): Is the problem that metrics a duplicated when following (non-containment) + throws NoSuchAlgorithmException, IOException, CoreException { + // TODO (#4333): Is the problem that metrics a duplicated when following (non-containment) // EReferences? // Is is only a problem when IProjectRoot elements (as for the allocation tables) are // referenced, or a general problem? A more general solution would be to adapt the model @@ -192,7 +176,7 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider // Sort root elements, as some metrics are saved into trees from other root elements // To avoid these problems, the elements have to be processed in a certain order - // TODO (SB): In case the model traversal strategy cannot be changed, the implementation + // TODO (#4333): In case the model traversal strategy cannot be changed, the implementation // below has to be generalized such that no knowledge about the AF3 metamodel is injected // into the kernel. @@ -216,6 +200,7 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider return 0; }); + var timestamp = LocalDateTime.now(); Map<IProjectRootElement, DataRootElement> updatedElements = new HashMap<>(); for(IProjectRootElement rootElement : rootElements) { MetricTreeNode rootNode = new MetricTreeNode(); @@ -237,7 +222,7 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider .stream().collect(groupingBy(IConstraintViolation::getSource)).entrySet()) { MetricTreeNode node = - metricDataManagerInstance.getTreeNodeLookupTable().get(entry.getKey()); + metricDataContainer.getTreeNodeLookupTable().get(entry.getKey()); if(node != null) { // Collect violations and store them in the error and warning metric @@ -250,14 +235,12 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider } } - // TODO (SB): I would remember the current timestamp once (i.e., before the outermost - // for-loop). That way, all metrics of the current run will have the same timestamp. If - // there is a reason to provide a current timestamp, you should provide a comment + // building the data Root Element DataRootElement dataRootElement = - new DataRootElement(LocalDateTime.now(), topLevelElement, rootNode); - metricDataManagerInstance.getDataRootElementMap().put(rootElement, dataRootElement); + new DataRootElement(timestamp, topLevelElement, rootNode); + metricDataContainer.getDataRootElementMap().put(rootElement, dataRootElement); updatedElements.put(rootElement, dataRootElement); - metricDataManagerInstance.getTreeNodeLookupTable().put(rootElement, rootNode); + metricDataContainer.getTreeNodeLookupTable().put(rootElement, rootNode); metricUpdateListeners.forEach(l -> l.metricUpdate(rootElement)); } // Store all currently saved metrics to the CSV file @@ -277,7 +260,7 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider private void recursivlyCollectMetrics(MetricTreeNode node, IHierarchicElement currentElement, int recursionLevel) { - var manager = metricDataManagerInstance; + var metricData = metricDataContainer; collectMetrics(node, currentElement); node.getStoredIntegers().put(MetricKey.NESTING_LEVEL, recursionLevel); @@ -295,7 +278,7 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider specificationElement.getContainedElements(); if(containedElements.size() == 1) { // Add reference from the element to this, so the lookups works as expected - manager.getTreeNodeLookupTable().put(specificationElement, node); + metricData.getTreeNodeLookupTable().put(specificationElement, node); // There is exactly one contained element. Skip the specification element to get a // more useful tree structure recursivlyCollectMetrics(node, containedElements.get(0), recursionLevel); @@ -303,7 +286,7 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider recursivlyCollectMetrics(node, specificationElement, recursionLevel); } // Add reference from the element to this, so the lookups works as expected - manager.getTreeNodeLookupTable().put(currentElement, node); + metricData.getTreeNodeLookupTable().put(currentElement, node); } else { // Iterate over all children and merge values var nodeDoubles = node.getStoredDoubles(); @@ -325,12 +308,11 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider } } - manager.getTreeNodeLookupTable().put(currentElement, node); - // TODO (SB): Why is the GraphMetricsProvider a special case? If possible, we should - // turn it into an ordinary metrics provider. Otherwise, we should create a ticket for a - // refactoring. - GraphMetricsProvider.calculateBetweennessCentrality(currentElement, manager, false); - GraphMetricsProvider.calculateBetweennessCentrality(currentElement, manager, true); + metricData.getTreeNodeLookupTable().put(currentElement, node); + + // TODO (#4332) Restructure GraphMetricsProvider in quality Plugin + GraphMetricsProvider.calculateBetweennessCentrality(currentElement, metricData, false); + GraphMetricsProvider.calculateBetweennessCentrality(currentElement, metricData, true); node.getStoredDoubles().put(MetricKey.CLUSTERING_COEFFICIENT, GraphMetricsProvider.calculateClusteringCoefficent(currentElement)); } @@ -351,10 +333,7 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider List<IMetricProvider<? extends EObject>> providers = getAllMetricProviders(object); for(IMetricProvider<? extends EObject> provider : providers) { - // TODO (SB): A nice solution would be to change getAllMetricProviders() to return a - // List<IMetricProvider<EObject>>. Can be postponed in a ticket with a TODO(#xyz) here - // The provider in the list has to have a compatible method for the actual type - // as we just collected providers with a compatible type + //TODO (#4331) ((IMetricProvider<EObject>)provider).collectMetrics(node, object); } } @@ -373,19 +352,19 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider /** {@inheritDoc} */ @Override protected String getExtensionPointName() { - return EXTENSION_POINT_NAME; + return null; } /** {@inheritDoc} */ @Override protected String getConfigurationElementName() { - return CONFIGURATION_ELEMENT_NAME; + return null; } /** {@inheritDoc} */ @Override protected String getHandlerClassAttribute() { - return ATTRIBUTE_NAME; + return null; } /** {@inheritDoc} */ @@ -422,15 +401,14 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider /** {@inheritDoc} */ @Override public void topLevelElementAdded(ITopLevelElement element) { - // Nothing done - // TODO (SB): I think this happens when the user copies a project to the storage view and - // "refresh"es. Is the "nothing done" intentional? Please check if my assumption is correct. + // Schedule the metric collection for a newly added project + scheduleMetricCollection(element); } /** {@inheritDoc} */ @Override public void topLevelElementRemoved(ITopLevelElement element) { - // Nothing done + // Nothing done so we keep the data } /** {@inheritDoc} */ @@ -438,11 +416,10 @@ public class ModelQualityService extends EObjectAwareServiceBase<IMetricProvider public void topLevelElementContentChanged(ITopLevelElement element) { scheduleMetricCollection(element); } - - // TODO (SB): The MetricDataManager (or MetricData, after the suggested renaming) is used by - // other classes => Expose on the IModelQualityService interface. - /** @return the {@link MetricDataManager} for this service instance. */ - public MetricDataManager getMetricDataManagerInstance() { - return metricDataManagerInstance; + + /** {@inheritDoc} */ + @Override + public MetricData getMetricData() { + return metricDataContainer; } } diff --git a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/storage/.ratings b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/storage/.ratings index 3ccb44dac7d09cee602524e970fb5e2571d03ef8..000e059c8703bc2a8b5a495edde3b0205eee5af9 100644 --- a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/storage/.ratings +++ b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/storage/.ratings @@ -1,2 +1,2 @@ -CSVFileWriter.java 7df3c06231037c5026ca7fa18572d935d444ebf7 RED -ModelQualityStorageManager.java 8293f17743bdc85e2595eae99b978ed868bd029b RED +CSVFileWriter.java 89ed8b8b05dbbe55c30bd416e9255e3896ca980c YELLOW +ModelQualityStorageManager.java c5a6783f51f596663bf836f98abf2b23130fe180 YELLOW diff --git a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/storage/CSVFileWriter.java b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/storage/CSVFileWriter.java index 7df3c06231037c5026ca7fa18572d935d444ebf7..89ed8b8b05dbbe55c30bd416e9255e3896ca980c 100644 --- a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/storage/CSVFileWriter.java +++ b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/storage/CSVFileWriter.java @@ -29,14 +29,16 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.commons.io.FilenameUtils; +import org.eclipse.core.runtime.CoreException; import org.fortiss.tooling.ext.quality.data.DataRootElement; import org.fortiss.tooling.ext.quality.data.MetricKey; +import org.fortiss.tooling.ext.quality.service.IModelQualityService; import org.fortiss.tooling.kernel.extension.data.ITopLevelElement; import org.fortiss.tooling.kernel.model.IProjectRootElement; @@ -47,16 +49,10 @@ import org.fortiss.tooling.kernel.model.IProjectRootElement; */ public class CSVFileWriter { - // TODO (SB): Comment is unclear. What is the default CSV file (I thought there are per-project - // metric files now)? What do you mean by the conversion? /** - * Method to write the data into the default CSV file. - * <p> - * It will always write to the same file, if it is already present it will attempt to read the - * keys and convert them into {@link MetricKey} and then write these keys in the ordering that - * is already present. This is done such that the log file always remains consistent, but can - * cause newly added {@link MetricKey} not to be exported if they were not present when the file - * was exported the first time. + * Method to write the data into CSV files. For each project one file is built. If it is already existant, + * it uses to the existing keys in the file as dimensions, to help that the log file always remains consistent. + * Newly added MetricKeys are not added in the next exportations if it was not present and build. * * @param map * to save into CSV file @@ -64,38 +60,31 @@ public class CSVFileWriter { * @throws NoSuchAlgorithmException * */ + + /** Suffix of the file in which the data is written. */ + private static final String CSV = ".csv"; + public static void metricExtractionToCSV(Map<IProjectRootElement, DataRootElement> map) - throws NoSuchAlgorithmException, IOException { + throws NoSuchAlgorithmException, IOException, CoreException { // check if there is any data to export if(map == null || map.isEmpty()) { return; } - - // TODO(SB): Move functionality to IModelQualityService (to which the directory is - // configured during startup, see comments in ModelQualityStorageManager) - // Ensure the folder exists - if(!ModelQualityStorageManager.MODEL_QUALITY_PROJECT_DIR.exists()) { - ModelQualityStorageManager.MODEL_QUALITY_PROJECT_DIR.mkdirs(); - } + + IModelQualityService.createQualityFolder(); // path to CSV file - // TODO (SB): What about the following (avoids creating an array): - // Check above is that iterator.next() returns at least one value - // DataRootElement firstValue = map.entrySet().iterator().next().getValue(); - Collection<DataRootElement> values = map.values(); - DataRootElement firstValue = values.toArray(new DataRootElement[0])[0]; + DataRootElement firstValue = map.entrySet().iterator().next().getValue(); ITopLevelElement topLevelElement = firstValue.getTopLevelElement(); String projectName = topLevelElement.getSaveableName(); - // TODO: the quality file name should be determined without knowledge of the AF3 file - // extension. Maybe FilenameUtils.getBaseName(filename) is useful? - Path path = new File(ModelQualityStorageManager.MODEL_QUALITY_PROJECT_DIR, projectName - .replace(ModelQualityStorageManager.AF3_PRJ_SUFFIX, ModelQualityStorageManager.CSV)) - .toPath(); + var fileBaseName = FilenameUtils.getBaseName(projectName).toString(); + Path path = new File(ModelQualityStorageManager.MODEL_QUALITY_PROJECT_DIR, fileBaseName.concat(CSV)).toPath(); - // TODO(SB): This assumes that the file has been saved to disk. - // Add topLevelElement.doSave(new NullProgressMonitor()); + //save before using the saved file to produce the hash + //FIXME (KB): produces unstoppable exceptions if I use it (IllegalStateExceptions) + //topLevelElement.doSave(new NullProgressMonitor()); Path modelFile = new File(ModelQualityStorageManager.MODEL_PROJECT_DIR, topLevelElement.getSaveableName()).toPath(); String projectHash = computeGitObjectHash(modelFile); @@ -142,18 +131,13 @@ public class CSVFileWriter { try(var writer = new BufferedWriter(new FileWriter(path.toFile(), true))) { if(createNewIndex) { - // TODO (SB): It would be save to start the (currently 6) non-value keys with the - // same (reserved) prefix. That way, we can later change the strategy to distinguish - // them for the value keys. The implementation below to assume that there are - // currently 6 non-value keys is fine. - // Create new index and write it into the first line of the file. - allKeys.add("timestamp"); - allKeys.add("project_name"); - allKeys.add("project_hash"); - allKeys.add("root_element_name"); - allKeys.add("name"); - allKeys.add("children"); + allKeys.add("nv_timestamp"); + allKeys.add("nv_project_name"); + allKeys.add("nv_project_hash"); + allKeys.add("nv_root_element_name"); + allKeys.add("nv_name"); + allKeys.add("nv_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) @@ -190,11 +174,12 @@ public class CSVFileWriter { // 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(k -> { - // TODO (SB): Always use braces for if. Avoids future problems :-) - if(k.isStringValue()) + if(k.isStringValue()) { return strings.get(k); - if(k.isDoubleValue()) + } + if(k.isDoubleValue()) { return doubles.get(k); + } return integers.get(k); }).map(String::valueOf)).collect(Collectors.joining(",")); try { diff --git a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/storage/ModelQualityStorageManager.java b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/storage/ModelQualityStorageManager.java index 8293f17743bdc85e2595eae99b978ed868bd029b..c5a6783f51f596663bf836f98abf2b23130fe180 100644 --- a/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/storage/ModelQualityStorageManager.java +++ b/org.fortiss.tooling.ext.quality/src/org/fortiss/tooling/ext/quality/storage/ModelQualityStorageManager.java @@ -21,10 +21,8 @@ import java.io.File; import org.eclipse.core.resources.IWorkspaceRoot; -// TODO (SB): This class is not really a manager, but a collection of constants. -// TODO (SB): This class makes the quality calculation AF3 specific. The suggested -// resolution is to distribute the information to other classes (as below). -// Possibly postpone this in a dedicated ticket, and reference it here (TODO (#xyz)) +// TODO (#4333) Exclude the constants to the corresponding packages. The suggested +// resolution is to distribute the information to other classes. /** * Manages the directory of the CSV files. * @@ -32,35 +30,27 @@ import org.eclipse.core.resources.IWorkspaceRoot; */ public class ModelQualityStorageManager { - // TODO(SB): Move to org.fortiss.af3.project (e.g., create sister class of AF3Project (e.g., + // TODO(#4333): Move to org.fortiss.af3.project (e.g., create sister class of AF3Project (e.g., // AF3Metrics), and configure the IModelQualityService from there with the directory name, etc.) /** The name of the general quality plugin directory. */ public static final String AF3_QUALITY_DIRECTORY_NAME = "AF3-Model-Quality-Directory"; - // TODO(SB): Remove! The single source of truth for this is + // TODO(#4333): Remove! The single source of truth for this is // org.fortiss.af3.project.utils.FileUtils /** The name of the general project directory. */ public static final String AF3_PROJECT_DIRECTORY_NAME = "AF3-Project-Directory"; - // TODO(SB): Remove (unneeded magic) + // TODO(#4333): Remove (unneeded magic) /** The current workspace root. */ public static final IWorkspaceRoot WORKSPACE_ROOT = getWorkspace().getRoot(); - // TODO(SB): Remove, see suggested AF3Metrics class above + // TODO(#4333): Remove, see suggested AF3Metrics class above /** {@link File} representing the directory where all data is saved. */ public static final File MODEL_QUALITY_PROJECT_DIR = new File(WORKSPACE_ROOT.getLocation() + File.separator + AF3_QUALITY_DIRECTORY_NAME); - // TODO(SB): Remove, see suggested AF3Metrics class above + // TODO(#4333): Remove, see suggested AF3Metrics class above /** {@link File} representing the directory where all data is saved. */ public static final File MODEL_PROJECT_DIR = new File(WORKSPACE_ROOT.getLocation() + File.separator + AF3_PROJECT_DIRECTORY_NAME); - - // TODO (SB): Remove! The single source of truth for this is org.fortiss.af3.project.AF3Project - /** Defines the suffix of AF3 project files. */ - public static final String AF3_PRJ_SUFFIX = "af3_23"; - - // TODO(SB): Move as (private) constant CSV_SUFFIX to CSVFileWriter - /** Suffix of the file in which the data is written. */ - public static final String CSV = "csv"; }