package it.unisa.sesa.repominer.metrics;
import it.unisa.sesa.repominer.db.ChangeDAO;
import it.unisa.sesa.repominer.db.ChangeForCommitDAO;
import it.unisa.sesa.repominer.db.ProjectDAO;
import it.unisa.sesa.repominer.db.TypeDAO;
import it.unisa.sesa.repominer.db.entities.Change;
import it.unisa.sesa.repominer.db.entities.ChangeForCommit;
import it.unisa.sesa.repominer.db.entities.Project;
import it.unisa.sesa.repominer.db.entities.SourceContainer;
import it.unisa.sesa.repominer.db.entities.Type;
import it.unisa.sesa.repominer.util.Utils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* This class is responsible to calculate all the history metrics relative to a
* package.
*
* @author RepominerEvo Team
*
*/
public class PackageMetrics {
private ChangeDAO changeDAO = new ChangeDAO();
private ProjectDAO projectDAO = new ProjectDAO();
private TypeDAO typeDAO = new TypeDAO();
private ChangeForCommitDAO changeForCommitDAO = new ChangeForCommitDAO();
/**
* This method calculate NR metric. The NR metric represent system number of
* revision
*
* @param pSourceContainer
* @return NR metric value
*/
public int getNumberOfAuthor(SourceContainer pSourceContainer) {
List<String> authors = new ArrayList<>();
List<Type> types = this.typeDAO.getClassesByPackage(pSourceContainer);
Project project = this.projectDAO.getProject(pSourceContainer
.getProjectId());
List<Change> changes = this.changeDAO.getChangesOfProject(project);
for (Change change : changes) {
List<ChangeForCommit> changesForCommit = this.changeForCommitDAO
.getChangeForCommitOfChange(change);
for (ChangeForCommit changeForCommit : changesForCommit) {
for (Type currType : types) {
if (currType.getSrcFileLocation().equals(
changeForCommit.getModifiedFile())) {
String author = change.getDevMail();
if (author == null || author.isEmpty()) {
author = change.getDevId();
}
if (!authors.contains(author)) {
authors.add(author);
}
break;
}
}
}
}
return authors.size();
}
/**
* This method calculate ChangeSetSize metric. The ChangeSetSize metric
* represent mean dimension of modified files in a package
*
* @param pSourceContainer
* @return ChangeSetSize metric value
*/
public double getMeanDimensionOfModifiedFiles(
SourceContainer pSourceContainer) {
List<Type> modifiedClassForPackage = this
.getModifiedClassForPackage(pSourceContainer);
float sumLines = 0;
// Return 0 if package has not changes
if (modifiedClassForPackage.size() == 0) {
return 0f;
}
for (Type type : modifiedClassForPackage) {
sumLines += type.getLinesNumber();
}
float meanLines = sumLines / modifiedClassForPackage.size();
return meanLines;
}
/**
* This method calculate mean_NCHANGE metric. The mean_NCHANGE metric
* represent mean number of file changes in a package
*
* @param pSourceContainer
* @return mean_NCHANGE metric value
*/
public double getMeanNumberOfChange(SourceContainer pSourceContainer) {
List<Type> modifiedClassForPackage = this
.getModifiedClassForPackage(pSourceContainer);
Map<String, Integer> occurrenceTable = new HashMap<>();
// We take all changes for a project
Project project = this.projectDAO.getProject(pSourceContainer
.getProjectId());
List<Change> changes = this.changeDAO.getChangesOfProject(project);
for (Type modifiedFile : modifiedClassForPackage) {
// Initialization of occurrenceTable with 0 occurrences
occurrenceTable.put(modifiedFile.getSrcFileLocation(), 0);
for (Change change : changes) {
List<ChangeForCommit> changesForCommit = this.changeForCommitDAO
.getChangeForCommitOfChange(change);
for (ChangeForCommit changeForCommit : changesForCommit) {
if (changeForCommit.getModifiedFile().equals(
modifiedFile.getSrcFileLocation())) {
int aux = occurrenceTable.get(modifiedFile
.getSrcFileLocation());
occurrenceTable.put(modifiedFile.getSrcFileLocation(),
aux + 1);
}
}
}
}
if (occurrenceTable.size() == 0) {
return 0.0;
}
double counter = 0.0;
// Iterating over occurrenceTable values
for (Integer occurenceValue : occurrenceTable.values()) {
counter += occurenceValue;
}
return counter / occurrenceTable.size();
}
/**
* This method calculate mean_NREF metric. The mean_NREF metric represent
* mean number of file changes in a package caused by refactoring operation
*
* @param pSourceContainer
* @return mean_NREF metric value
*/
public double getMeanNumberOfChangeForRefactoring(
SourceContainer pSourceContainer) {
List<Type> modifiedClassForPackage = this
.getModifiedClassForPackage(pSourceContainer);
Map<String, Integer> occurrenceTable = new HashMap<>();
// We take all changes for a project
Project project = this.projectDAO.getProject(pSourceContainer
.getProjectId());
List<Change> changes = this.changeDAO.getChangesOfProject(project);
for (Type modifiedFile : modifiedClassForPackage) {
// Initialization of occurrenceTable with 0 occurrences
occurrenceTable.put(modifiedFile.getSrcFileLocation(), 0);
for (Change change : changes) {
if (!Utils.msgIsRefactoring(change.getMessage())) {
continue;
}
List<ChangeForCommit> changesForCommit = this.changeForCommitDAO
.getChangeForCommitOfChange(change);
for (ChangeForCommit changeForCommit : changesForCommit) {
if (changeForCommit.getModifiedFile().equals(
modifiedFile.getSrcFileLocation())) {
int aux = occurrenceTable.get(modifiedFile
.getSrcFileLocation());
occurrenceTable.put(modifiedFile.getSrcFileLocation(),
aux + 1);
}
}
}
}
if (occurrenceTable.size() == 0) {
return 0.0;
}
double counter = 0.0;
// Iterating over occurrenceTable values
for (Integer occurenceValue : occurrenceTable.values()) {
counter += occurenceValue;
}
return counter / occurrenceTable.size();
}
/**
* This method calculate mean_NFIX metric. The mean_NFIX metric represent
* mean number of file changes in a package caused by bug fixes
*
* @param pSourceContainer
* @return mean_NFIX metric value
*/
public double getMeanNumberOfChangeForBugFix(
SourceContainer pSourceContainer) {
List<Type> modifiedClassForPackage = this
.getModifiedClassForPackage(pSourceContainer);
Map<String, Integer> occurrenceTable = new HashMap<>();
// We take all changes for a project
Project project = this.projectDAO.getProject(pSourceContainer
.getProjectId());
List<Change> changes = this.changeDAO.getChangesOfProject(project);
for (Type modifiedFile : modifiedClassForPackage) {
// Initialization of occurrenceTable with 0 occurrences
occurrenceTable.put(modifiedFile.getSrcFileLocation(), 0);
for (Change change : changes) {
if (!Utils.msgIsBugFixing(change.getMessage())) {
continue;
}
List<ChangeForCommit> changesForCommit = this.changeForCommitDAO
.getChangeForCommitOfChange(change);
for (ChangeForCommit changeForCommit : changesForCommit) {
if (changeForCommit.getModifiedFile().equals(
modifiedFile.getSrcFileLocation())) {
int aux = occurrenceTable.get(modifiedFile
.getSrcFileLocation());
occurrenceTable.put(modifiedFile.getSrcFileLocation(),
aux + 1);
}
}
}
}
if (occurrenceTable.size() == 0) {
return 0.0;
}
double counter = 0.0;
// Iterating over occurrenceTable values
for (Integer occurenceValue : occurrenceTable.values()) {
counter += occurenceValue;
}
return counter / occurrenceTable.size();
}
/**
* This method calculate the first value of Lines metric, namely sum of
* insertion or deletion
*
* @param pSourceContainer
* @return First value for Lines metric
*/
public Integer getTotalInsertionsOrDeletionsNumber(
SourceContainer pSourceContainer) {
int sum = 0;
List<Type> types = this.typeDAO.getClassesByPackage(pSourceContainer);
Project project = this.projectDAO.getProject(pSourceContainer
.getProjectId());
List<Change> changes = this.changeDAO.getChangesOfProject(project);
for (Change change : changes) {
List<ChangeForCommit> changesForCommit = this.changeForCommitDAO
.getChangeForCommitOfChange(change);
for (ChangeForCommit changeForCommit : changesForCommit) {
for (Type currType : types) {
if (currType.getSrcFileLocation().equals(
changeForCommit.getModifiedFile())) {
int insOrDel = changeForCommit.getInsertions()
+ changeForCommit.getDeletions();
sum += insOrDel;
break;
}
}
}
}
return sum;
}
/**
* This method calculate the second value of Lines metric, namely max number
* of insertion or deletion
*
* @param pSourceContainer
* @return Second value for Lines metric
*/
public Integer getMaxInsertionsOrDeletionsNumber(
SourceContainer pSourceContainer) {
int max = 0;
List<Type> types = this.typeDAO.getClassesByPackage(pSourceContainer);
Project project = this.projectDAO.getProject(pSourceContainer
.getProjectId());
List<Change> changes = this.changeDAO.getChangesOfProject(project);
for (Change change : changes) {
List<ChangeForCommit> changesForCommit = this.changeForCommitDAO
.getChangeForCommitOfChange(change);
for (ChangeForCommit changeForCommit : changesForCommit) {
for (Type currType : types) {
if (currType.getSrcFileLocation().equals(
changeForCommit.getModifiedFile())) {
int insOrDel = changeForCommit.getInsertions()
+ changeForCommit.getDeletions();
if (insOrDel > max)
max = insOrDel;
break;
}
}
}
}
return max;
}
/**
* This method calculate the third value of Lines metric, namely mean number
* of insertion or deletion
*
* @param pSourceContainer
* @return Third value for Lines metric
*/
public Double getMeanInsertionsOrDeletionsNumber(
SourceContainer pSourceContainer) {
double sum = 0;
int howMany = 0;
List<Type> types = this.typeDAO.getClassesByPackage(pSourceContainer);
Project project = this.projectDAO.getProject(pSourceContainer
.getProjectId());
List<Change> changes = this.changeDAO.getChangesOfProject(project);
for (Change change : changes) {
List<ChangeForCommit> changesForCommit = this.changeForCommitDAO
.getChangeForCommitOfChange(change);
for (ChangeForCommit changeForCommit : changesForCommit) {
for (Type currType : types) {
if (currType.getSrcFileLocation().equals(
changeForCommit.getModifiedFile())) {
int insOrDel = changeForCommit.getInsertions()
+ changeForCommit.getDeletions();
sum += insOrDel;
howMany++;
break;
}
}
}
}
if (howMany == 0) {
return new Double(0.0);
} else {
return new Double(sum / howMany);
}
}
/**
* This method calculate the Lines metric. The Lines metric represent the
* total, mean an maximum number of insertion or deletion
*
* @param pSourceContainer
* @return Lines metric value
*/
public Double[] getInsertionsAndDelitionsInfo(
SourceContainer pSourceContainer) {
Double[] info = new Double[3];
double sum = 0.0;
int max = 0;
double howMany = 0.0;
List<Type> types = this.typeDAO.getClassesByPackage(pSourceContainer);
Project project = this.projectDAO.getProject(pSourceContainer
.getProjectId());
List<Change> changes = this.changeDAO.getChangesOfProject(project);
for (Change change : changes) {
List<ChangeForCommit> changesForCommit = this.changeForCommitDAO
.getChangeForCommitOfChange(change);
for (ChangeForCommit changeForCommit : changesForCommit) {
for (Type currType : types) {
if (currType.getSrcFileLocation().equals(
changeForCommit.getModifiedFile())) {
int insOrDel = changeForCommit.getInsertions()
+ changeForCommit.getDeletions();
if (insOrDel > max)
max = insOrDel;
sum += insOrDel;
howMany++;
break;
}
}
}
}
info[0] = new Double(sum);
if (howMany == 0) {
info[1] = new Double(0.0);
} else {
info[1] = new Double(sum / howMany);
}
info[2] = new Double(max);
return info;
}
/**
* This method get a list of class that have been changed in a package
*
* @param pSourceContainer
* @return A list of Type objects
*/
private List<Type> getModifiedClassForPackage(
SourceContainer pSourceContainer) {
List<Type> modifiedClassForPackage = new ArrayList<>();
List<Type> types = this.typeDAO.getClassesByPackage(pSourceContainer);
Project project = this.projectDAO.getProject(pSourceContainer
.getProjectId());
List<Change> changes = this.changeDAO.getChangesOfProject(project);
for (Change change : changes) {
// We take and iterate all changes_for_commit of this package
List<ChangeForCommit> changesForCommit = new ChangeForCommitDAO()
.getChangeForCommitOfChange(change);
for (ChangeForCommit changeForCommit : changesForCommit) {
for (Type type : types) {
if (type.getSrcFileLocation().equals(
changeForCommit.getModifiedFile())) {
if (!modifiedClassForPackage.contains(type)) {
modifiedClassForPackage.add(type);
}
}
}
}
}
return modifiedClassForPackage;
}
}