Package br.edu.utfpr.cm.JGitMinerWeb.services.metric

Source Code of br.edu.utfpr.cm.JGitMinerWeb.services.metric.CochangeStructuralHolesMeasureServices

package br.edu.utfpr.cm.JGitMinerWeb.services.metric;

import br.edu.utfpr.cm.JGitMinerWeb.dao.GenericDao;
import br.edu.utfpr.cm.JGitMinerWeb.model.matrix.EntityMatrix;
import br.edu.utfpr.cm.JGitMinerWeb.model.matrix.EntityMatrixNode;
import br.edu.utfpr.cm.JGitMinerWeb.model.miner.EntityCommit;
import br.edu.utfpr.cm.JGitMinerWeb.model.miner.EntityCommitFile;
import br.edu.utfpr.cm.JGitMinerWeb.model.miner.EntityCommitUser;
import br.edu.utfpr.cm.JGitMinerWeb.model.miner.EntityRepository;
import br.edu.utfpr.cm.JGitMinerWeb.model.miner.EntityRepositoryCommit;
import br.edu.utfpr.cm.JGitMinerWeb.services.matrix.UserCommentedSamePairOfFileInDateServices;
import br.edu.utfpr.cm.JGitMinerWeb.services.matrix.UserModifySamePairOfFileInDateServices;
import br.edu.utfpr.cm.JGitMinerWeb.services.matrix.auxiliary.AuxFileFile;
import br.edu.utfpr.cm.JGitMinerWeb.services.matrix.auxiliary.AuxUserUser;
import br.edu.utfpr.cm.JGitMinerWeb.services.metric.auxiliary.AuxFileFileMetrics;
import br.edu.utfpr.cm.JGitMinerWeb.services.metric.structuralholes.StructuralHolesMeasure;
import br.edu.utfpr.cm.JGitMinerWeb.services.metric.structuralholes.StructuralHolesCalculator;
import br.edu.utfpr.cm.JGitMinerWeb.util.JsfUtil;
import br.edu.utfpr.cm.JGitMinerWeb.util.OutLog;
import edu.uci.ics.jung.graph.UndirectedGraph;
import edu.uci.ics.jung.graph.UndirectedSparseGraph;
import edu.uci.ics.jung.graph.util.EdgeType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* Measure structural holes metrics based on graph of co-change with weighted edges.
* The result of measure is about the edges. An edge represents a pair of files
* (i.e. two files has changed in same pull request), in a timeframe.
* To calculate the metric, we sum the measure of the every vertex that
* connected with these pair of file.
*
* @author Rodrigo T. Kuroda <rodrigokuroda at gmail dot com>
*/
public class CochangeStructuralHolesMeasureServices extends AbstractMetricServices {

    private EntityRepository repository;

    private static final String CALCULE_SUM_UPDATES_OF_TWO_FILE =
            "SELECT count(1) FROM " + EntityRepositoryCommit.class.getSimpleName() + " rc "
            + "JOIN " + EntityCommit.class.getSimpleName() + " c ON rc.commit = c "
            + "JOIN " + EntityCommitUser.class.getSimpleName() + " u ON c.committer = u "
            + "JOIN " + EntityCommitFile.class.getSimpleName() + " f ON f.repositoryCommit = rc "
            + "WHERE "
            + "rc.repository = :repo AND "
            + "u.dateCommitUser BETWEEN :beginDate AND :endDate AND "
            + "(f.filename = :fileName OR f.filename = :fileName2)";

    private static final String[] CALCULE_SUM_UPDATES_OF_TWO_FILE_PARAMS = new String[]{
        "repo", "fileName", "fileName2", "beginDate", "endDate"
    };

    private static final String CALCULE_UPDATES =
            "SELECT COUNT(rc) FROM EntityRepositoryCommit rc "
            + "WHERE "
            + "rc.repository = :repo AND "
            + "rc.commit.committer.dateCommitUser BETWEEN :beginDate AND :endDate AND "
            + "EXISTS (SELECT f FROM EntityCommitFile f WHERE f.repositoryCommit = rc AND f.filename = :fileName) AND "
            + "EXISTS (SELECT f2 FROM EntityCommitFile f2 WHERE f2.repositoryCommit = rc AND f2.filename = :fileName2)";

    private static final String[] CALCULE_UPDATES_PARAMS = new String[]{
        "repo", "fileName", "fileName2", "beginDate", "endDate"
    };

   
    public CochangeStructuralHolesMeasureServices(GenericDao dao, OutLog out) {
        super(dao, out);
    }

    public CochangeStructuralHolesMeasureServices(GenericDao dao, EntityMatrix matrix, Map params, OutLog out) {
        super(dao, matrix, params, out);
    }

    public Date getBeginDate() {
        Calendar beginDateCalendar = Calendar.getInstance();
        beginDateCalendar.setTime(getDateParam("beginDate"));
        beginDateCalendar.set(Calendar.HOUR_OF_DAY, 0);
        beginDateCalendar.set(Calendar.MINUTE, 0);
        beginDateCalendar.set(Calendar.SECOND, 0);
        beginDateCalendar.set(Calendar.MILLISECOND, 0);
        return beginDateCalendar.getTime();
    }

    public Date getEndDate() {
        Calendar endDateCalendar = Calendar.getInstance();
        endDateCalendar.setTime(getDateParam("endDate"));
        endDateCalendar.set(Calendar.HOUR_OF_DAY, 23);
        endDateCalendar.set(Calendar.MINUTE, 59);
        endDateCalendar.set(Calendar.SECOND, 59);
        endDateCalendar.set(Calendar.MILLISECOND, 999);
        return endDateCalendar.getTime();
    }

    @Override
    public void run() {
        System.out.println(params);

        System.out.println(getMatrix().getClassServicesName());
       
        Date beginDate = getBeginDate();
        Date endDate = getEndDate();
        Date futureBeginDate = getFutureBeginDate();
        Date futureEndDate = getFutureEndDate();

        if (getMatrix() == null
                || !getAvailableMatricesPermitted().contains(getMatrix().getClassServicesName())) {
            throw new IllegalArgumentException("Selecione uma matrix gerada pelo Services: " + getAvailableMatricesPermitted());
        }

        repository = getRepository();

        if (repository == null) {
            throw new IllegalArgumentException("Não foi possível encontrar o repositório utilizado nesta matrix.");
        }

        System.out.println("Selecionado matrix com " + getMatrix().getNodes().size() + " nodes.");
        final UndirectedGraph<String, String> graph = new UndirectedSparseGraph<>();
       
        final Map<String, Integer> edgeWeigth = new HashMap<>(getMatrix().getNodes().size());
        final Map<AuxFileFile, Set<String>> commitersPairFile = new HashMap<>();
        final Map<AuxFileFile, Long> pairFileCommitCount = new HashMap<>();
       
        final Set<String> distinctDevelopers = new HashSet<>();
        final Set<String> distinctFiles = new HashSet<>();
       
        Set<AuxFileFile> pairFiles = new HashSet<>();
        Map<String, AuxFileFile> edgeFiles = new HashMap<>();
        for (int i = 0; i < getMatrix().getNodes().size(); i++) {
            EntityMatrixNode node = getMatrix().getNodes().get(i);
            String[] columns = node.getLine().split(JsfUtil.TOKEN_SEPARATOR);
           
            AuxFileFile pairFile = new AuxFileFile(columns[1], columns[2]);
            AuxUserUser pairUser = new AuxUserUser(columns[0], columns[3]);
           
            // to count unique developers
            distinctDevelopers.add(pairUser.getUser());
            distinctDevelopers.add(pairUser.getUser2());
           
            /**
             * Extract all distinct developer that commit a pair of file
             */
            if (commitersPairFile.containsKey(pairFile)) {
                Set<String> commiters = commitersPairFile.get(pairFile);
                commiters.add(pairUser.getUser());
                commiters.add(pairUser.getUser2());
            } else {
                Set<String> commiters = new HashSet<>();
                commiters.add(pairUser.getUser());
                commiters.add(pairUser.getUser2());
                commitersPairFile.put(pairFile, commiters);
            }
           
            String edgeName = pairUser.toString();
           
            // to count unique files
            distinctFiles.add(pairFile.getFileName());
            distinctFiles.add(pairFile.getFileName2());
           
            pairFiles.add(pairFile);
            edgeFiles.put(edgeName, pairFile);
           
            String weightedEdge = (String) params.get("weightedEdge");
            if ("false".equalsIgnoreCase(weightedEdge)) {
                // binary edge weight
                edgeWeigth.put(edgeName, 1);
            } else {
                /* Sum commit for each pair file that the pair dev has commited. */
                if (edgeWeigth.containsKey(pairUser.toStringUserAndUser2())) {
                    // edgeName = user + user2
                    edgeWeigth.put(pairUser.toStringUserAndUser2(), edgeWeigth.get(pairUser.toStringUserAndUser2()) + Integer.valueOf(columns[4]));
                } else if (edgeWeigth.containsKey(pairUser.toStringUser2AndUser())) {
                    // edgeName = user2 + user
                    edgeWeigth.put(pairUser.toStringUser2AndUser(), edgeWeigth.get(pairUser.toStringUser2AndUser()) + Integer.valueOf(columns[4]));
                } else {
                    edgeWeigth.put(edgeName, Integer.valueOf(columns[4]));
                }
            }
           
            if (!pairFileCommitCount.containsKey(pairFile)) {
                pairFileCommitCount.put(pairFile,
                        calculeSumUpdatesOfTwoFile(pairFile.getFileName(), pairFile.getFileName2(), beginDate, endDate));
            }
           
            /**
             * The co-change network is constructed as follow:
             * If developer A and developer B commits a pair file PF, then they are connected in network.
             */
            if (!graph.containsVertex(pairUser.getUser())
                    || !graph.containsVertex(pairUser.getUser2())
                    || !graph.isNeighbor(pairUser.getUser(), pairUser.getUser2())) {
                graph.addEdge(edgeName, pairUser.getUser(), pairUser.getUser2(), EdgeType.UNDIRECTED);
            }
        }
        out.printLog("Weigth of edges:");
        for (Map.Entry<String, Integer> entry : edgeWeigth.entrySet()) {
            out.printLog(entry.getKey() + " " + entry.getValue());
        }
        out.printLog("End of weigth of edges.");

        /**
         * Calculates structural holes metrics for each developer on the co-change network based.
         */
        Map<String, StructuralHolesMeasure<String>> metricsResult =
                StructuralHolesCalculator.calcule(graph, edgeWeigth);
       
        /**
         * For each pair of file, calculate the sum, average, and max of each
         * structural holes metrics of developer that commited the pair of file.
         */
        List<AuxFileFileMetrics> structuralHolesMetrics = new ArrayList<>(pairFiles.size());
        for (AuxFileFile pairFile : pairFiles) {
            double efficiencyMax = 0, efficiencyAvg, efficiencySum = 0;
            double effectiveSizeMax = 0, effectiveSizeAvg, effectiveSizeSum = 0;
            double constraintMax = 0, constraintAvg, constraintSum = 0;
            double hierarchyMax = 0, hierarchyAvg, hierarchySum = 0;
            long developers = 0;
            for (String commiter : commitersPairFile.get(pairFile)) {
                StructuralHolesMeasure<String> commiterMetric = metricsResult.get(commiter);
                double efficiency = commiterMetric.getEfficiency();
                double effectiveSize = commiterMetric.getEffectiveSize();
                double constraint = commiterMetric.getConstraint();
                double hierarchy = commiterMetric.getHierarchy();
               
                efficiencySum += efficiency;
                effectiveSizeSum += effectiveSize;
                constraintSum += constraint;
                hierarchySum += hierarchy;
               
                efficiencyMax = Math.max(efficiencyMax, efficiency);
                effectiveSizeMax = Math.max(effectiveSizeMax, effectiveSize);
                constraintMax = Math.max(constraintMax, constraint);
                hierarchyMax = Math.max(hierarchyMax, hierarchy);
               
                developers++;
            }
            efficiencyAvg = efficiencySum / developers;
            effectiveSizeAvg = effectiveSizeSum / developers;
            constraintAvg = constraintSum / developers;
            hierarchyAvg = hierarchySum / developers;
           
            Long updates =
                    calculeUpdates(pairFile.getFileName(), pairFile.getFileName2(),
                            beginDate, endDate);
            Long futureUpdates =
                    calculeUpdates(pairFile.getFileName(), pairFile.getFileName2(),
                            futureBeginDate, futureEndDate);
           
            structuralHolesMetrics.add(
                    new AuxFileFileMetrics(
                        pairFile.getFileName(), pairFile.getFileName2(),
                        efficiencySum, efficiencyAvg, efficiencyMax,
                        effectiveSizeSum, effectiveSizeAvg, effectiveSizeMax,
                        constraintSum, constraintAvg, constraintMax,
                        hierarchySum, hierarchyAvg, hierarchyMax,
                        developers, pairFileCommitCount.get(pairFile), updates, futureUpdates));
        }
       
        addToEntityMetricNodeList(structuralHolesMetrics);
       
        out.printLog("Distinct developers: " + distinctDevelopers.size());
        out.printLog("Distinct files: " + distinctFiles.size());
    }

    @Override
    public String getHeadCSV() {
        return "file1;file2;"
                + "efficiencySum;efficiencyAvg;efficiencyMax;"
                + "effectiveSizeSum;effectiveSizeAvg;effectiveSizeMax;"
                + "constraintSum;constraintAvg;constraintMax;"
                + "hierarchySum;hierarchyAvg;hierarchyMax;"
                + "developers;commits;updates;futureUpdates"
                ;
    }

    @Override
    public List<String> getAvailableMatricesPermitted() {
        return Arrays.asList(
                UserModifySamePairOfFileInDateServices.class.getName(),
                UserCommentedSamePairOfFileInDateServices.class.getName()
        );
    }
   
    private Long calculeSumUpdatesOfTwoFile(String fileName, String fileName2, Date beginDate, Date endDate) {
        if (beginDate == null || endDate == null) {
            return 0l;
        }
       
        Object[] queryParams = new Object[]{
            repository,
            fileName,
            fileName2,
            beginDate,
            endDate
        };

        return dao.selectOneWithParams(CALCULE_SUM_UPDATES_OF_TWO_FILE, CALCULE_SUM_UPDATES_OF_TWO_FILE_PARAMS, queryParams);
    }
   
    private Long calculeUpdates(String fileName, String fileName2, Date beginDate, Date endDate) {
        if (beginDate == null || endDate == null) {
            return 0l;
        }
       
        Object[] queryParams = new Object[]{
            repository,
            fileName,
            fileName2,
            beginDate,
            endDate
        };

        return dao.selectOneWithParams(CALCULE_UPDATES, CALCULE_UPDATES_PARAMS, queryParams);
    }
   
    private Long calculeUpdatesForCommiterPair(String fileName, String fileName2, String commiter, String commiter2,
            Date beginDate, Date endDate) {
        if (beginDate == null || endDate == null) {
            return 0l;
        }
        String jpql = "SELECT COUNT(rc) "
                + "FROM "
                + "EntityRepositoryCommit rc "
                + "WHERE "
                + "rc.repository = :repo AND "
                + "rc.commit.committer.dateCommitUser BETWEEN :beginDate AND :endDate AND "
                + "EXISTS (SELECT f FROM EntityCommitFile f WHERE f.repositoryCommit = rc AND f.filename = :fileName) AND "
                + "EXISTS (SELECT f2 FROM EntityCommitFile f2 WHERE f2.repositoryCommit = rc AND f2.filename = :fileName2) AND "
                + "("
                  + "("
                    + "(rc.commit.commiter.email IS NOT NULL AND rc.commit.commiter.email = :commiter) OR "
                    + "(rc.commit.commiter.name IS NOT NULL AND rc.commit.commiter.name = :commiter) "
                  + ") OR ("
                    + "(rc.commit.commiter.email IS NOT NULL AND rc.commit.commiter.email = :commiter2) OR "
                    + "(rc.commit.commiter.name IS NOT NULL AND rc.commit.commiter.name = :commiter2) "
                  + ")"
                + ")";

        String[] bdParams = new String[]{
            "repo",
            "fileName",
            "fileName2",
            "beginDate",
            "endDate",
            "commiter",
            "commiter2"
        };
        Object[] bdObjects = new Object[]{
            repository,
            fileName,
            fileName2,
            beginDate,
            endDate,
            commiter,
            commiter2
        };

        return dao.selectOneWithParams(jpql, bdParams, bdObjects);
    }
   
    public Date getFutureBeginDate() {
        Calendar futureBeginDateCalendar = Calendar.getInstance();
        futureBeginDateCalendar.setTime(getDateParam("futureBeginDate"));
        futureBeginDateCalendar.set(Calendar.HOUR_OF_DAY, 0);
        futureBeginDateCalendar.set(Calendar.MINUTE, 0);
        futureBeginDateCalendar.set(Calendar.SECOND, 0);
        futureBeginDateCalendar.set(Calendar.MILLISECOND, 0);
        return futureBeginDateCalendar.getTime();
    }

    public Date getFutureEndDate() {
        Calendar futureEndDateCalendar = Calendar.getInstance();
        futureEndDateCalendar.setTime(getDateParam("futureEndDate"));
        futureEndDateCalendar.set(Calendar.HOUR_OF_DAY, 23);
        futureEndDateCalendar.set(Calendar.MINUTE, 59);
        futureEndDateCalendar.set(Calendar.SECOND, 59);
        futureEndDateCalendar.set(Calendar.MILLISECOND, 999);
        return futureEndDateCalendar.getTime();
    }

    private EntityRepository getRepository() {
        String[] repoStr = getMatrix().getRepository().split("/");
        List<EntityRepository> repos = dao.executeNamedQueryWithParams(
                "Repository.findByNameAndOwner",
                new String[]{"login", "name"},
                new Object[]{repoStr[0], repoStr[1]});
        if (repos.size() == 1) {
            return repos.get(0);
        }
        return null;
    }
}
TOP

Related Classes of br.edu.utfpr.cm.JGitMinerWeb.services.metric.CochangeStructuralHolesMeasureServices

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.