package net.certware.measurement.spm.view.handlers; import java.util.Date; import net.certware.core.ui.log.CertWareLog; import net.certware.measurement.smm.Accumulator; import net.certware.measurement.smm.AggregatedMeasurement; import net.certware.measurement.smm.Annotation; import net.certware.measurement.smm.BinaryMeasure; import net.certware.measurement.smm.CollectiveMeasure; import net.certware.measurement.smm.DimensionalMeasure; import net.certware.measurement.smm.DimensionalMeasurement; import net.certware.measurement.smm.DirectMeasurement; import net.certware.measurement.smm.Measurement; import net.certware.measurement.smm.Observation; import net.certware.measurement.smm.SmmFactory; import net.certware.measurement.spm.AdaptabilityRatioMeasure; import net.certware.measurement.spm.AdaptabilityTrend; import net.certware.measurement.spm.BaselineCaseSizeMeasure; import net.certware.measurement.spm.BrokenCaseSizeMeasure; import net.certware.measurement.spm.CriticalAndNormalChangeOrderCount; import net.certware.measurement.spm.CriticalDefectChangeOrderCount; import net.certware.measurement.spm.DevelopmentEffortMeasure; import net.certware.measurement.spm.EndProductQuality; import net.certware.measurement.spm.FixedCaseSizeMeasure; import net.certware.measurement.spm.ImprovementChangeOrderCount; import net.certware.measurement.spm.InProgressIndicator; import net.certware.measurement.spm.MaintainabilityMeasure; import net.certware.measurement.spm.MaturityRatioMeasure; import net.certware.measurement.spm.MaturityTrend; import net.certware.measurement.spm.ModularityMeasure; import net.certware.measurement.spm.ModularityTrend; import net.certware.measurement.spm.NewFeatureChangeOrderCount; import net.certware.measurement.spm.NormalDefectChangeOrderCount; import net.certware.measurement.spm.ProjectCommit; import net.certware.measurement.spm.ProjectModel; import net.certware.measurement.spm.ProjectScope; import net.certware.measurement.spm.RepairEffortMeasure; import net.certware.measurement.spm.ReworkBacklogMeasure; import net.certware.measurement.spm.ReworkRatioMeasure; import net.certware.measurement.spm.ReworkStabilityMeasure; import net.certware.measurement.spm.ScrapRatioMeasure; import net.certware.measurement.spm.SpmFactory; import net.certware.measurement.spm.TimeDimensionalMeasure; import net.certware.measurement.spm.TotalCaseSizeMeasure; import net.certware.measurement.spm.TotalChangeOrderCount; import net.certware.measurement.spm.TrendMeasure; import net.certware.measurement.spm.UsageTimeMeasure; import net.certware.measurement.spm.view.Activator; import net.certware.measurement.spm.view.preferences.PreferenceConstants; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.ecore.EObject; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.ui.ISelectionService; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.handlers.HandlerUtil; /** * Computes change order metrics. * @author mrb * @since 2.0.0 */ public class ComputeMetricsHandler extends AbstractHandler { /** part selected in command context */ IWorkbenchPart latestPart = null; /** measure library tag */ public static final String LIBRARY_TAG = "CertWare"; /** functor value for divide */ public static final String FUNCTOR_DIVIDE = "divide"; //$NON-NLS-1$ /** functor value for subtract */ public static final String FUNCTOR_SUBTRACT = "subtract"; //$NON-NLS-1$ /** functor value for add */ public static final String FUNCTOR_ADD = "add"; //$NON-NLS-1$ /** functor value for multiply */ public static final String FUNCTOR_MULTIPLY = "multiply"; //$NON-NLS-1$ /** observation tool value tag */ public static final String OBSERVATION_TOOL = "CertWare"; /** observation observer tag */ public static final String OBSERVATION_OBSERVER = "Computed"; /** measurement error value */ public static final String MEASUREMENT_ERROR = "Computed"; /** * Handles the compute metrics command request. * Presumes the command came from a popup menu selection of model or commit. * @param event used to find context * @return always returns null * @throws ExecutionException if open fails * @see org.eclipse.core.commands.IHandler#execute(ExecutionEvent) */ @Override public Object execute(ExecutionEvent event) throws ExecutionException { try { // fetch workbench context latestPart = HandlerUtil.getActivePartChecked(event); IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindowChecked(event); ISelectionService service = window.getSelectionService(); IStructuredSelection iss = (IStructuredSelection)service.getSelection(); Object first = iss.getFirstElement(); // project commit if ( first instanceof ProjectCommit ) { ProjectCommit pc = (ProjectCommit)first; if ( computeMetrics(pc) == true ) { return null; } } // project model selection, do for each commit if ( first instanceof ProjectModel ) { // check raw statistics and compute metrics ProjectModel pm = (ProjectModel)first; for ( ProjectCommit pc : pm.getCommits() ) { if ( computeMetrics(pc) == true ) { // nothing logged per commit } } return null; } } catch (ExecutionException e) { CertWareLog.logError("Opening SCO view", e); } return null; } /** * Compute the metrics given a project commit. * Check whether the raw statistics are present. * Updates the model elements in the given commit. * @param pm project model to check * @return true if all necessary statistics are present and have measurements */ public boolean computeMetrics(ProjectCommit pc) { CriticalDefectChangeOrderCount cdcoc = null; NormalDefectChangeOrderCount ndcoc = null; ImprovementChangeOrderCount icoc = null; NewFeatureChangeOrderCount nfcoc = null; TotalChangeOrderCount tcoc = null; CriticalAndNormalChangeOrderCount cncoc = null; BrokenCaseSizeMeasure brokenSize = null; FixedCaseSizeMeasure fixedSize = null; TotalCaseSizeMeasure totalSize = null; BaselineCaseSizeMeasure baselineSize = null; UsageTimeMeasure usageTime = null; DevelopmentEffortMeasure developmentEffort = null; RepairEffortMeasure repairEffort = null; ModularityTrend modularityTrend = null; AdaptabilityTrend adaptabilityTrend = null; AdaptabilityRatioMeasure adaptabilityRatio = null; ModularityMeasure modularity = null; ReworkBacklogMeasure reworkBacklog = null; ReworkRatioMeasure reworkRatio = null; ReworkStabilityMeasure reworkStability = null; MaintainabilityMeasure maintainability = null; MaturityTrend maturityTrend = null; MaturityRatioMeasure maturityRatio = null; ScrapRatioMeasure scrapRatio = null; EndProductQuality endProductQuality = null; InProgressIndicator inProgressIndicator = null; ProjectScope projectScope = null; // preferences IPreferenceStore store = Activator.getDefault().getPreferenceStore(); boolean clearMeasurements = store.getBoolean(PreferenceConstants.P_CLEAR_MEASUREMENTS); // gather individual statistics by iterating over all commit elements TreeIterator<?> ti = pc.eAllContents(); while( ti.hasNext() ) { EObject eo = (EObject)ti.next(); // scopes if ( eo instanceof ProjectScope ) { projectScope = (ProjectScope)eo; continue; } // statistics if ( eo instanceof CriticalDefectChangeOrderCount ) { cdcoc = (CriticalDefectChangeOrderCount)eo; continue; } if ( eo instanceof NormalDefectChangeOrderCount ) { ndcoc = (NormalDefectChangeOrderCount)eo; continue; } if ( eo instanceof ImprovementChangeOrderCount ) { icoc = (ImprovementChangeOrderCount)eo; continue; } if ( eo instanceof NewFeatureChangeOrderCount ) { nfcoc = (NewFeatureChangeOrderCount)eo; continue; } if ( eo instanceof TotalChangeOrderCount ) { tcoc = (TotalChangeOrderCount)eo; continue; } if ( eo instanceof CriticalAndNormalChangeOrderCount ) { cncoc = (CriticalAndNormalChangeOrderCount)eo; continue; } if ( eo instanceof BrokenCaseSizeMeasure ) { brokenSize = (BrokenCaseSizeMeasure)eo; continue; } if ( eo instanceof FixedCaseSizeMeasure ) { fixedSize = (FixedCaseSizeMeasure)eo; continue; } if ( eo instanceof TotalCaseSizeMeasure ) { totalSize = (TotalCaseSizeMeasure)eo; continue; } if ( eo instanceof BaselineCaseSizeMeasure ) { baselineSize = (BaselineCaseSizeMeasure)eo; continue; } if ( eo instanceof UsageTimeMeasure ) { usageTime = (UsageTimeMeasure)eo; continue; } if ( eo instanceof DevelopmentEffortMeasure ) { developmentEffort = (DevelopmentEffortMeasure)eo; continue; } if ( eo instanceof RepairEffortMeasure ) { repairEffort = (RepairEffortMeasure)eo; continue; } // computed metrics if ( eo instanceof ScrapRatioMeasure ) { scrapRatio = (ScrapRatioMeasure)eo; continue; } if ( eo instanceof MaturityRatioMeasure ) { maturityRatio = (MaturityRatioMeasure)eo; continue; } if ( eo instanceof MaturityTrend ) { maturityTrend = (MaturityTrend)eo; continue; } if ( eo instanceof MaintainabilityMeasure ) { maintainability = (MaintainabilityMeasure)eo; continue; } if ( eo instanceof ReworkStabilityMeasure ) { reworkStability = (ReworkStabilityMeasure)eo; continue; } if ( eo instanceof ReworkRatioMeasure ) { reworkRatio = (ReworkRatioMeasure)eo; continue; } if ( eo instanceof ReworkBacklogMeasure ) { reworkBacklog = (ReworkBacklogMeasure)eo; continue; } if ( eo instanceof ModularityMeasure ) { modularity = (ModularityMeasure)eo; continue; } if ( eo instanceof AdaptabilityRatioMeasure) { adaptabilityRatio = (AdaptabilityRatioMeasure)eo; continue; } if ( eo instanceof AdaptabilityTrend) { adaptabilityTrend = (AdaptabilityTrend)eo; continue; } if ( eo instanceof ModularityTrend) { modularityTrend = (ModularityTrend)eo; continue; } // categories if ( eo instanceof EndProductQuality) { endProductQuality = (EndProductQuality)eo; continue; } if ( eo instanceof InProgressIndicator) { inProgressIndicator = (InProgressIndicator)eo; } } // for commit // check input statistics // creates a list of missing items, if any StringBuffer sb = new StringBuffer(); if ( projectScope == null ) { // try to find in parent model projectScope = findProjectScopeFromCommit(pc); if ( projectScope == null ) { sb.append("Project scope").append('\n'); } } if ( cdcoc == null ) { sb.append("Critical defect change order count").append('\n'); } if ( ndcoc == null ) { sb.append("Normal defect change order count").append('\n'); } if ( icoc == null ) { sb.append("Improvement change order count").append('\n'); } if ( nfcoc == null ) { sb.append("New feature change order count").append('\n'); } if ( tcoc == null ) { sb.append("Total change order count").append('\n'); } if ( cncoc == null ) { sb.append("Critical and normal change order count").append('\n'); } if ( brokenSize == null ) { sb.append("Broken case size").append('\n'); } if ( fixedSize == null ) { sb.append("Fixed case size").append('\n'); } if ( totalSize == null ) { sb.append("Total case size").append('\n'); } if ( baselineSize == null ) { sb.append("Baselined case size").append('\n'); } if ( usageTime == null ) { sb.append("Usage time").append('\n'); } if ( developmentEffort == null ) { sb.append("Development effort").append('\n'); } if ( repairEffort == null ) { sb.append("Repair effort").append('\n'); } // if any statistic missing, report and return if ( sb.length() > 0 ) { sb.insert(0, "The following statistics are missing:\n"); reportIncomplete(sb.toString()); return false; } // check whether categories are already present // if not, create them and add to the project commit if ( endProductQuality == null ) { endProductQuality = SpmFactory.eINSTANCE.createEndProductQuality(); endProductQuality.setName("End Product Quality"); pc.getModelElement().add(endProductQuality); CertWareLog.logInfo("Added end product quality characteristic to project commit"); } if ( inProgressIndicator == null ) { inProgressIndicator = SpmFactory.eINSTANCE.createInProgressIndicator(); inProgressIndicator.setName("In-Progress Indicator"); pc.getModelElement().add(inProgressIndicator); CertWareLog.logInfo("Added in-progress indicator characteristic to project commit"); } // check whether metrics are already present // in-progress quality if ( modularityTrend == null ) { modularityTrend = SpmFactory.eINSTANCE.createModularityTrend(); modularityTrend.setName("Modularity Trend"); modularityTrend.setBaseMeasure(modularity); modularityTrend.setLibrary(LIBRARY_TAG); modularityTrend.setScope(projectScope); modularityTrend.setTrait(inProgressIndicator); modularityTrend.setAccumulator(Accumulator.AVERAGE); modularityTrend.setUnit("SLOC/order-hr"); modularityTrend.setTrait(inProgressIndicator); CertWareLog.logInfo("Added modularity trend measure to project commit"); } if ( adaptabilityTrend == null ) { adaptabilityTrend = SpmFactory.eINSTANCE.createAdaptabilityTrend(); adaptabilityTrend.setName("Adaptability Trend"); adaptabilityTrend.setBaseMeasure(adaptabilityRatio); adaptabilityTrend.setLibrary(LIBRARY_TAG); adaptabilityTrend.setScope(projectScope); adaptabilityTrend.setAccumulator(Accumulator.AVERAGE); adaptabilityTrend.setUnit("hr/SLOC-hr"); adaptabilityTrend.setTrait(inProgressIndicator); CertWareLog.logInfo("Added adaptability trend measure to project commit"); } if ( maturityTrend == null ) { maturityTrend = SpmFactory.eINSTANCE.createMaturityTrend(); maturityTrend.setName("Maturity Trend"); maturityTrend.setBaseMeasure(maturityRatio); maturityTrend.setLibrary(LIBRARY_TAG); maturityTrend.setScope(projectScope); maturityTrend.setAccumulator(Accumulator.AVERAGE); maturityTrend.setUnit("hr/SLOC-hr"); maturityTrend.setTrait(inProgressIndicator); CertWareLog.logInfo("Added maturity trend measure to project commit"); } if ( reworkStability == null ) { reworkStability = SpmFactory.eINSTANCE.createReworkStabilityMeasure(); reworkStability.setName("Rework Stability"); reworkStability.setLibrary(LIBRARY_TAG); reworkStability.setFunctor("subtract"); reworkStability.setBaseMeasure1(brokenSize); reworkStability.setBaseMeasure2(fixedSize); reworkStability.setUnit("SLOC"); reworkStability.setScope(projectScope); reworkStability.setTrait(inProgressIndicator); CertWareLog.logInfo("Added rework stability measure to project commit"); } if ( reworkBacklog == null ) { reworkBacklog = SpmFactory.eINSTANCE.createReworkBacklogMeasure(); reworkBacklog.setName("Rework Backlog"); reworkBacklog.setLibrary(LIBRARY_TAG); reworkBacklog.setBaseMeasure1(reworkStability); reworkBacklog.setBaseMeasure2(baselineSize); reworkBacklog.setFunctor(FUNCTOR_DIVIDE); reworkBacklog.setUnit(""); reworkBacklog.setScope(projectScope); reworkBacklog.setTrait(inProgressIndicator); CertWareLog.logInfo("Added rework backlog measure to project commit"); } // end-product quality if ( scrapRatio == null ) { scrapRatio = SpmFactory.eINSTANCE.createScrapRatioMeasure(); scrapRatio.setName("Scrap Ratio"); scrapRatio.setLibrary(LIBRARY_TAG); scrapRatio.setBaseMeasure1(brokenSize); scrapRatio.setBaseMeasure2(totalSize); scrapRatio.setFunctor(FUNCTOR_DIVIDE); scrapRatio.setUnit(""); scrapRatio.setScope(projectScope); scrapRatio.setTrait(endProductQuality); CertWareLog.logInfo("Added scrap ratio measure to project commit"); } if ( adaptabilityRatio == null ) { adaptabilityRatio = SpmFactory.eINSTANCE.createAdaptabilityRatioMeasure(); adaptabilityRatio.setName("Adaptability"); adaptabilityRatio.setLibrary(LIBRARY_TAG); adaptabilityRatio.setBaseMeasure1(repairEffort); adaptabilityRatio.setBaseMeasure2(tcoc); adaptabilityRatio.setFunctor(FUNCTOR_DIVIDE); adaptabilityRatio.setUnit("hr/SLOC"); adaptabilityRatio.setScope(projectScope); adaptabilityRatio.setTrait(endProductQuality); CertWareLog.logInfo("Added adaptability ratio measure to project commit"); } if ( modularity == null ) { modularity = SpmFactory.eINSTANCE.createModularityMeasure(); modularity.setName("Modularity"); modularity.setLibrary(LIBRARY_TAG); modularity.setBaseMeasure1(brokenSize); modularity.setBaseMeasure2(tcoc); modularity.setFunctor(FUNCTOR_DIVIDE); modularity.setUnit(""); modularity.setScope(projectScope); modularity.setTrait(endProductQuality); CertWareLog.logInfo("Added modularity measure to project commit"); } if ( reworkRatio == null ) { reworkRatio = SpmFactory.eINSTANCE.createReworkRatioMeasure(); reworkRatio.setName("Rework Ratio"); reworkRatio.setLibrary(LIBRARY_TAG); reworkRatio.setBaseMeasure1(repairEffort); reworkRatio.setBaseMeasure2(developmentEffort); reworkRatio.setFunctor(FUNCTOR_DIVIDE); reworkRatio.setUnit(""); reworkRatio.setScope(projectScope); reworkRatio.setTrait(endProductQuality); CertWareLog.logInfo("Added rework ratio measure to project commit"); } if ( maintainability == null ) { maintainability = SpmFactory.eINSTANCE.createMaintainabilityMeasure(); maintainability.setName("Maintainability"); maintainability.setLibrary(LIBRARY_TAG); maintainability.setBaseMeasure1(scrapRatio); maintainability.setBaseMeasure2(reworkRatio); maintainability.setFunctor(FUNCTOR_DIVIDE); maintainability.setUnit(""); maintainability.setScope(projectScope); maintainability.setTrait(endProductQuality); CertWareLog.logInfo("Added maintainability measure to project commit"); } if ( maturityRatio == null ) { maturityRatio = SpmFactory.eINSTANCE.createMaturityRatioMeasure(); maturityRatio.setName("Maturity Ratio"); maturityRatio.setLibrary(LIBRARY_TAG); maturityRatio.setBaseMeasure1(usageTime); maturityRatio.setBaseMeasure2(cncoc); maturityRatio.setFunctor(FUNCTOR_DIVIDE); maturityRatio.setUnit("hr/order"); maturityRatio.setScope(projectScope); maturityRatio.setTrait(endProductQuality); CertWareLog.logInfo("Added maturity ratio measure to project commit"); } // at this point we have all statistics, and the categories and metrics are in the commit // compute metrics, putting the measurement values into the front of the measurement list computeMetric( modularityTrend, clearMeasurements ); computeMetric( adaptabilityTrend, clearMeasurements ); computeMetric( maturityTrend, clearMeasurements ); computeMetric( reworkStability, clearMeasurements ); computeMetric( reworkBacklog, clearMeasurements ); computeMetric( scrapRatio, clearMeasurements ); computeMetric( adaptabilityRatio, clearMeasurements); computeMetric( modularity, clearMeasurements ); computeMetric( reworkRatio, clearMeasurements ); computeMetric( maintainability, clearMeasurements ); computeMetric( maturityRatio, clearMeasurements ); String name = getName(pc); CertWareLog.logInfo(String.format("%s %s","Computed core metrics for commit",name)); return true; } /** * Finds the project scope element in the project model container. * @param pc project commit, presumed to be contained by a project model element * @return project scope element or null if not found searching the project model */ private ProjectScope findProjectScopeFromCommit(ProjectCommit pc) { ProjectModel pm = (ProjectModel)pc.eContainer(); TreeIterator<?> ti = pm.eAllContents(); while( ti.hasNext() ) { EObject eo = (EObject)ti.next(); if ( eo instanceof ProjectScope ) { return (ProjectScope)eo; } } return null; } /** * Gets a list of the annotations attached to a project commit element. * Builds the list with each annotation separated by a comma character. * @param pc project commit * @return string delimited by commas */ private String getName(ProjectCommit pc) { EList<Annotation> annotations = pc.getAnnotation(); StringBuffer sb = new StringBuffer(); boolean subsequentPass = false; for ( Annotation a : annotations ) { if ( subsequentPass ) { sb.append( ',' ); } sb.append( a.getText() ); subsequentPass = true; } return sb.toString(); } /** * Computes the averages of the items in the measurement list. * @param items list of measurement items, assumed to be {@code DimensionalMeasurement} types. * @return average, or {@code POSITIVE_INFINITY} if count of dimensional measurement is zero. */ protected double computeAverage(EList<Measurement> items) { double sum = 0.0; int n = 0; for ( Measurement measurement : items ) { if ( measurement instanceof DimensionalMeasurement ) { DimensionalMeasurement dm = (DimensionalMeasurement)measurement; sum += dm.getValue(); n++; } } if ( n == 0 ) return Double.POSITIVE_INFINITY; return sum / n; } /** * Computes the maximum of the items in the measurement list. * @param items list of measurement items, assumed to be {@code DimensionalMeasurement} types. * @return average, or {@code NaN} if count of dimensional measurement is zero. */ protected double computeMaximum(EList<Measurement> items) { double max = Double.NaN; for ( Measurement measurement : items ) { if ( measurement instanceof DimensionalMeasurement ) { DimensionalMeasurement dm = (DimensionalMeasurement)measurement; if ( max == Double.NaN ) { max = dm.getValue(); } else { max = Math.max(max, dm.getValue()); } } } return max; } /** * Computes the minimum of the items in the measurement list. * @param items list of measurement items, assumed to be {@code DimensionalMeasurement} types. * @return average, or {@code NaN} if count of dimensional measurement is zero. */ protected double computeMinimum(EList<Measurement> items) { double min = Double.NaN; for ( Measurement measurement : items ) { if ( measurement instanceof DimensionalMeasurement ) { DimensionalMeasurement dm = (DimensionalMeasurement)measurement; if ( min == Double.NaN ) { min = dm.getValue(); } else { min = Math.min(min, dm.getValue()); } } } return min; } /** * Creates an observation record to be attached to a computed metric measurement. * @return observation with tool, observer, and when-observed fields set */ public Observation computeObservation() { Observation obs = SmmFactory.eINSTANCE.createObservation(); obs.setObserver(OBSERVATION_OBSERVER); obs.setTool(OBSERVATION_TOOL); obs.setWhenObserved(new Date()); return obs; } /** * Computes a trend measure's results given its base measurement and values. * Assumes the single base measure is a dimensional measure with measurements available. * Uses the measurement at index zero from the base measure. * Inserts the result as a measurement at index zero for the given trend measure. * Creates an observation to attach to the measurement with the current time stamp. * @param tm trend measure, the aggregation type is unused here (e.g. average not performed) * @param clear whether to clear the measurement results list before inserting new result at front * @return true if computation completed without encountering nulls */ public boolean computeMetric( TrendMeasure tm, boolean clear ) { // check that the measure and measurement is not null DimensionalMeasure dm = tm.getBaseMeasure(); if ( dm == null ) { return false; } if ( dm.getMeasurement() == null ) { return false; } double answer = Double.NaN; // compute answer based on accumulator if ( tm.getAccumulator() == Accumulator.AVERAGE ) { answer = computeAverage( dm.getMeasurement() ); } else if ( tm.getAccumulator() == Accumulator.MAXIMUM ) { answer = computeMaximum( dm.getMeasurement() ); } else if ( tm.getAccumulator() == Accumulator.MINIMUM ) { answer = computeMinimum( dm.getMeasurement() ); } // create an observation reflecting calculated value Observation obs = computeObservation(); // create a new measurement with this answer and observation AggregatedMeasurement result = SmmFactory.eINSTANCE.createAggregatedMeasurement(); result.setValue(answer); result.setObservation(obs); result.setError(MEASUREMENT_ERROR); // whether to clear earlier measurements from the results measurement list if ( clear ) { dm.getMeasurement().clear(); } // insert the measurement at the front of the measurement list dm.getMeasurement().add(0, result); return true; } /** * Computes a binary measure's results given its base measurements and values. * Assumes both base measures are dimensional measures with measurements available. * Uses the measurement at index zero from each base measure. * Inserts the result as a measurement at index zero for the given binary measure. * Creates an observation to attach to the measurement with the current time stamp. * @param bm binary measure, using functor value to identify math operation * @param clear whether to clear the measurement results list before inserting new result at front * @return true if computation completed without encountering nulls or divides-by-zero */ public boolean computeMetric( BinaryMeasure bm, boolean clear ) { // check that the measures and measurements are not null DimensionalMeasure m1 = bm.getBaseMeasure1(); DimensionalMeasure m2 = bm.getBaseMeasure2(); if ( m1 == null || m2 == null ) { return false; } if ( m1.getMeasurement() == null || m2.getMeasurement() == null ) { return false; } DimensionalMeasurement s1 = (DimensionalMeasurement) m1.getMeasurement().get(0); DimensionalMeasurement s2 = (DimensionalMeasurement) m2.getMeasurement().get(0); if ( s1 == null || s2 == null ) { return false; } // compute answer based on functor value double answer = 0.0; if ( bm.getFunctor() == null ) { CertWareLog.logWarning(String.format("%s %s","Missing functor in binary measure",bm.getName())); return false; } if ( bm.getFunctor().equalsIgnoreCase(FUNCTOR_ADD) ) { answer = s1.getValue() + s2.getValue(); } else if ( bm.getFunctor().equalsIgnoreCase(FUNCTOR_DIVIDE) ) { if ( s2.getValue() == 0.0 ) return false; answer = s1.getValue() / s2.getValue(); } else if ( bm.getFunctor().equalsIgnoreCase(FUNCTOR_MULTIPLY)) { answer = s1.getValue() * s2.getValue(); } else if ( bm.getFunctor().equalsIgnoreCase(FUNCTOR_SUBTRACT)) { answer = s1.getValue() - s2.getValue(); } // create an observation reflecting calculated value Observation obs = computeObservation(); // create a new measurement with this answer and observation AggregatedMeasurement result = SmmFactory.eINSTANCE.createAggregatedMeasurement(); result.setValue(answer); result.setObservation(obs); result.setError(MEASUREMENT_ERROR); // whether to clear earlier measurements from the results measurement list if ( clear ) { bm.getMeasurement().clear(); } // insert the measurement at the front of the measurement list bm.getMeasurement().add(0, result); return true; } /** * Sets a statistic value by creating a new measurement to attach to the measure. * Presumes statistic is a collective measure, attaching a direct measurement. * @param statistic statistic measure * @param value statistic value * @param clear whether to clear the measurement list * @return false if statistic is null, true otherwise */ public boolean setStatistic(CollectiveMeasure statistic, double value, boolean clear) { if ( statistic == null ) return false; DirectMeasurement dm = SmmFactory.eINSTANCE.createDirectMeasurement(); dm.setValue(value); dm.setObservation( computeObservation() ); dm.setError(MEASUREMENT_ERROR); if ( clear ) { statistic.getMeasurement().clear(); } // insert the measurement at the front statistic.getMeasurement().add(0, dm); return true; } /** * Sets a statistic value by creating a new measurement to attach to the measure. * Presumes statistic is a time-dimensional measure, attaching a direct measurement. * @param statistic statistic measure * @param value statistic value * @param clear whether to clear the measurement list * @return false if statistic is null, true otherwise */ public boolean setStatistic(TimeDimensionalMeasure statistic, double value, boolean clear) { if ( statistic == null ) return false; DirectMeasurement dm = SmmFactory.eINSTANCE.createDirectMeasurement(); dm.setValue(value); dm.setObservation( computeObservation() ); dm.setError(MEASUREMENT_ERROR); if ( clear ) { statistic.getMeasurement().clear(); } // insert the measurement at the front statistic.getMeasurement().add(0, dm); return true; } /** * Reports a warning that a prerequisite statistic is missing. * @param message message to display to log and message dialog */ private void reportIncomplete(String message) { CertWareLog.logWarning(message); if ( latestPart != null && latestPart.getSite() != null ) { MessageDialog.openWarning(latestPart.getSite().getShell(), "Statistics Incomplete", message); } } }