/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package br.uff.ic.oceano.ostra.service;
import br.uff.ic.oceano.core.tools.metrics.MetricException;
import br.uff.ic.oceano.core.exception.ObjetoNaoEncontradoException;
import br.uff.ic.oceano.core.exception.ServiceException;
import br.uff.ic.oceano.core.factory.MetricManagerFactory;
import br.uff.ic.oceano.core.model.Metric;
import br.uff.ic.oceano.core.model.MetricValue;
import br.uff.ic.oceano.core.model.Revision;
import br.uff.ic.oceano.core.model.SoftwareProject;
import br.uff.ic.oceano.core.tools.metrics.MetricManager;
import br.uff.ic.oceano.core.tools.metrics.expression.QMOOD;
import static br.uff.ic.oceano.core.tools.metrics.expression.QMOOD.*;
import br.uff.ic.oceano.util.NumberUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* @author DanCastellani
*/
public class OstraQualityAtributesWithout_HardCoded_Service extends OstraMetricService {
private static final boolean STOP_WITH_ERRORS = false;
List<MetricManager> qualityAttributes;
List<MetricManager> qmoodMetrics;
public OstraQualityAtributesWithout_HardCoded_Service() {
super();
qmoodMetrics = MetricManagerFactory.getQmoodMetrics();
qualityAttributes = MetricManagerFactory.getQmoodQualityAttributes();
}
public void calculateQualityAttributes(SoftwareProject project) throws MetricException, ServiceException {
Map<String, Double> firstValues = new HashMap<String, Double>();
System.out.print("Calculating Quality Attributes for project " + project);
// I - get all revisions on time order
ArrayList<Revision> revisions = new ArrayList<Revision>(revisionService.getByProject(project));
Collections.sort(revisions);
boolean firstRevision = true;
for (Revision revision : revisions) {
System.out.println("\n=== Revision: " + revision);
//I.a ignore revisions that dont compile, because they dont have all the metrics
//may not be true for non Java projects
// boolean cannotCompile = revision.getCannotCompile()==null?true:revision.getCannotCompile();
// if (cannotCompile) {
// System.out.println(" ===> Cannot compile. Skipping...");
// continue;
// }
//II - get and normalize the qmood metric values by the first revisions values
System.out.println(" Getting QMOOD metrics ");
final Map<String, Double> mapMetricValues = getQmoodMetricValues(revision);
if (mapMetricValues.entrySet().size() < QMOOD.QMOOD_METRICS.length) {
System.out.println("[!!!] Skipping revision: " + revision + ". Not enough metrics");
continue;
}
final Map<String, Double> mapMetricValuesNormalized = new HashMap<String, Double>(mapMetricValues.size());
//II.a store the first values
if (firstRevision) {
for (String qmoodMetric : mapMetricValues.keySet()) {
firstValues.put(qmoodMetric, mapMetricValues.get(qmoodMetric));
if (mapMetricValues.get(qmoodMetric) != 0D) {
mapMetricValuesNormalized.put(qmoodMetric, 1D);
} else {
mapMetricValuesNormalized.put(qmoodMetric, 0D);
}
}
firstRevision = false;
} else {
//II.b normalize
System.out.println(" Normalizing values");
for (String qmoodMetric : mapMetricValues.keySet()) {
//update the first value that can be used.
if (firstValues.get(qmoodMetric) == 0D) {
if (mapMetricValues.get(qmoodMetric) != 0D) {
System.out.println("=== Updating first value (was zero): " + qmoodMetric + " = " + mapMetricValues.get(qmoodMetric));
firstValues.put(qmoodMetric, mapMetricValues.get(qmoodMetric));
}
}
Double normalizedValue = mapMetricValues.get(qmoodMetric);
if (firstValues.get(qmoodMetric) != 0D) {
normalizedValue /= firstValues.get(qmoodMetric);
}
normalizedValue = NumberUtil.roundDecimal(normalizedValue);
mapMetricValuesNormalized.put(qmoodMetric, normalizedValue);
}
}
System.out.println(" Original Metric Values = " + mapMetricValues);
System.out.println(" Normalized Metric Values = " + mapMetricValuesNormalized);
//III - calculate and save the quality attributes
System.out.println(" Calculating Quality Attributes");
for (MetricManager qualityAttribute : qualityAttributes) {
// III.a calculate quality atribute value
Double calculatedQualityAttribute = calculateQualityAttribute(qualityAttribute.getMetric().getName(), mapMetricValuesNormalized);
// III.b save it
final MetricValue metricValueQualityAttribute = new MetricValue(revision, qualityAttribute.getMetric(), calculatedQualityAttribute);
metricValueService.save(metricValueQualityAttribute);
System.out.println(" QA: " + metricValueQualityAttribute);
}
}
}
private Double calculateQualityAttribute(String qmoodQualityAttribute, Map<String, Double> mvs) throws MetricException {
if (qmoodQualityAttribute.equals(QA_EFFECTIVENESS)) {
return 0.2 * mvs.get(ABSTRACTION) + 0.2 * mvs.get(ENCAPSULATION) + 0.2 * mvs.get(COMPOSITION) + 0.2 * mvs.get(INHERITANCE) + 0.2 * mvs.get(POLYMORPHISM);
}
if (qmoodQualityAttribute.equals(QA_EXTENDABILITY)) {
return 0.5 * mvs.get(ABSTRACTION) - 0.5 * mvs.get(COUPLING) + 0.5 * mvs.get(INHERITANCE) + 0.5 * mvs.get(POLYMORPHISM);
}
if (qmoodQualityAttribute.equals(QA_FLEXIBILITY)) {
return 0.25 * mvs.get(ENCAPSULATION) - 0.25 * mvs.get(COUPLING) + 0.5 * mvs.get(COMPOSITION) + 0.5 * mvs.get(POLYMORPHISM);
}
if (qmoodQualityAttribute.equals(QA_FUNCTIONALITY)) {
return 0.12 * mvs.get(COHESION) + 0.22 * mvs.get(POLYMORPHISM) + 0.22 * mvs.get(MESSAGING) + 0.22 * mvs.get(DESIGN_SIZE) + 0.22 * mvs.get(HIERARCHIES);
}
if (qmoodQualityAttribute.equals(QA_REUSABILITY)) {
return -0.25 * mvs.get(COUPLING) + 0.25 * mvs.get(COHESION) + 0.5 * mvs.get(MESSAGING) + 0.5 * mvs.get(DESIGN_SIZE);
}
if (qmoodQualityAttribute.equals(QA_UNDERSTANDABILITY)) {
return -0.33 * mvs.get(ABSTRACTION) + 0.33 * mvs.get(ENCAPSULATION) - 0.33 * mvs.get(COUPLING) + 0.33 * mvs.get(COHESION) - 0.33 * mvs.get(POLYMORPHISM) - 0.33 * mvs.get(COMPLEXITY) - 0.33 * mvs.get(DESIGN_SIZE);
}
throw new MetricException("This is not a QMOOD Quality Attribute");
}
private Map<String, Double> getQmoodMetricValues(Revision revision) throws ServiceException {
Map<String, Double> mapQmoodMetricValues = new HashMap<String, Double>(QMOOD_METRICS.length);
for (MetricManager qmoodMetric : qmoodMetrics) {
try {
MetricValue metricValue = metricValueService.getByRevisionMetricAndDelta(revision, qmoodMetric.getMetric(), false);
mapQmoodMetricValues.put(qmoodMetric.getMetric().getAcronym(), metricValue.getDoubleValue());
} catch (ObjetoNaoEncontradoException ex) {
if (STOP_WITH_ERRORS) {
throw new ServiceException("Revision " + revision + " dont have the metric: " + qmoodMetric);
} else {
System.out.println(" >>>>>>>>>>>> Revision " + revision + " dont have the metric: " + qmoodMetric);
}
}
}
return mapQmoodMetricValues;
}
}