de.fosd.jdime.stats.ASTStats.java Source code

Java tutorial

Introduction

Here is the source code for de.fosd.jdime.stats.ASTStats.java

Source

/*
 * Copyright (C) 2013-2014 Olaf Lessenich
 * Copyright (C) 2014-2015 University of Passau, Germany
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301  USA
 *
 * Contributors:
 *     Olaf Lessenich <lessenic@fim.uni-passau.de>
 */
package de.fosd.jdime.stats;

import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.TreeSet;

import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import de.fosd.jdime.common.LangElem;

/**
 * TODO: high-level documentation
 * 
 * @author Olaf Lessenich
 * 
 */
public class ASTStats {
    private static final Logger LOG = Logger.getLogger(ClassUtils.getShortClassName(ASTStats.class));

    public static ASTStats add(final ASTStats a, final ASTStats b) {
        ASTStats sum = null;
        try {
            sum = (ASTStats) a.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            System.exit(-1);
        }
        sum.add(b);
        return sum;
    }

    /**
     * Map of diff statistics.
     */
    private HashMap<String, StatsElement> diffstats;

    private boolean hasChanges = false;

    /**
     * Maximum number of children at a level of the AST.
     */
    private int maxchildren = 0;

    /**
     * Number of AST nodes.
     */
    private int nodes = 0;

    /**
     * Depth of AST.
     */
    private int treedepth = 0;

    private int fragments = 0;

    /**
     * Creates a new ASTStats instance.
     * 
     * @param nodes
     *            number of AST nodes
     * @param treedepth
     *            depth of AST
     * @param maxchildren
     *            maximum number of children at an AST level
     * @param diffstats
     *            diff statistics
     */
    public ASTStats(final int nodes, final int treedepth, final int maxchildren,
            final HashMap<String, StatsElement> diffstats, final boolean hasChanges) {
        this.nodes = nodes;
        this.treedepth = treedepth;
        this.maxchildren = maxchildren;
        this.diffstats = diffstats;
        this.hasChanges = hasChanges;
    }

    public final void add(ASTStats other) {
        nodes += other.nodes;
        fragments += other.fragments;

        if (other.treedepth > treedepth) {
            treedepth = other.treedepth;
        }

        if (other.maxchildren > maxchildren) {
            maxchildren = other.maxchildren;
        }

        for (String key : other.diffstats.keySet()) {
            assert (diffstats.containsKey(key)) : "Error: Key '" + key + "' not found!";
            // if (diffstats.containsKey(key)) {
            diffstats.get(key).addStatsElement(other.diffstats.get(key));
            // }
        }

        if (!hasChanges) {
            hasChanges = other.hasChanges();
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#clone()
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        ASTStats clone = new ASTStats(nodes, treedepth, maxchildren, diffstats, hasChanges);
        clone.setFragments(fragments);
        HashMap<String, StatsElement> diffstatsClone = new HashMap<>();

        for (String key : diffstats.keySet()) {
            diffstatsClone.put(key, diffstats.get(key).copy());
        }

        clone.setDiffstats(diffstatsClone);
        return clone;
    }

    /**
     * @return the diffstats
     */
    public final HashMap<String, StatsElement> getDiffstats() {
        return diffstats;
    }

    public StatsElement getDiffStats(String key) {
        return diffstats.get(key);
    }

    /**
     * @return the maxchildren
     */
    public final int getMaxchildren() {
        return maxchildren;
    }

    /**
     * @return the nodes
     */
    public final int getNodes() {
        return nodes;
    }

    /**
     * @return the treedepth
     */
    public final int getTreedepth() {
        return treedepth;
    }

    public boolean hasChanges() {
        return hasChanges;
    }

    public void hasChanges(boolean hasChanges) {
        this.hasChanges = hasChanges;
    }

    public final void incrementNodes() {
        nodes++;
    }

    public final void incrementTreeDepth() {
        treedepth++;
    }

    public final void setConflicts(ASTStats other) {
        for (String key : other.diffstats.keySet()) {
            assert (diffstats.containsKey(key)) : "Error: Key '" + key + "' not found!";
            StatsElement mystats = diffstats.get(key);
            StatsElement otherstats = other.diffstats.get(key);
            assert mystats.getConflicting() == 0 : "Unexpected: conflicts > 0";
            mystats.setConflicting(otherstats.getConflicting());
        }
    }

    public final void setRemovalsfromAdditions(ASTStats other) {
        for (String key : other.diffstats.keySet()) {
            assert (diffstats.containsKey(key)) : "Error: Key '" + key + "' not found!";
            StatsElement mystats = diffstats.get(key);
            StatsElement otherstats = other.diffstats.get(key);
            mystats.setDeleted(otherstats.getAdded());
        }
    }

    public final void setRemovalsfromMatches(ASTStats other) {
        for (String key : other.diffstats.keySet()) {
            assert (diffstats.containsKey(key)) : "Error: Key '" + key + "' not found!";
            StatsElement mystats = diffstats.get(key);
            StatsElement otherstats = other.diffstats.get(key);
            mystats.setDeleted(otherstats.getMatches());
        }
    }

    public final void setAdditionsfromMatches(ASTStats other) {
        for (String key : other.diffstats.keySet()) {
            assert (diffstats.containsKey(key)) : "Error: Key '" + key + "' not found!";
            StatsElement mystats = diffstats.get(key);
            StatsElement otherstats = other.diffstats.get(key);
            mystats.setAdded(otherstats.getMatches());
        }
    }

    public final void resetRemovals() {
        for (String key : diffstats.keySet()) {
            StatsElement mystats = diffstats.get(key);
            mystats.setDeleted(0);
        }
    }

    public final void resetAdditions() {
        for (String key : diffstats.keySet()) {
            StatsElement mystats = diffstats.get(key);
            mystats.setAdded(0);
        }
    }

    /**
     * @param diffstats
     *            the diffstats to set
     */
    public final void setDiffstats(final HashMap<String, StatsElement> diffstats) {
        this.diffstats = diffstats;
    }

    /**
     * @param maxchildren
     *            the maxchildren to set
     */
    public final void setMaxchildren(final int maxchildren) {
        this.maxchildren = maxchildren;
    }

    /**
     * @param nodes
     *            the nodes to set
     */
    public final void setNodes(final int nodes) {
        this.nodes = nodes;
    }

    /**
     * @param treedepth
     *            the treedepth to set
     */
    public final void setTreedepth(final int treedepth) {
        this.treedepth = treedepth;
    }

    /**
     * @return the fragments
     */
    public int getFragments() {
        return fragments;
    }

    /**
     * @param fragments
     *            the fragments to set
     */
    public void setFragments(int fragments) {
        this.fragments = fragments;
    }

    public double getAvgFragmentSize() {
        return fragments == 0 ? 0.0
                : (double) diffstats.get(LangElem.NODE.toString()).getChanges() / (double) fragments;
    }

    public void incrementFragments() {
        assert (hasChanges());
        this.fragments++;
    }

    @Override
    public String toString() {
        DecimalFormat df = new DecimalFormat("#.0");

        StringBuilder sb = new StringBuilder();

        if (LOG.isDebugEnabled()) {
            sb.append("Total nodes: " + nodes + System.lineSeparator());
            sb.append("Treedepth: " + treedepth + System.lineSeparator());
            sb.append("Maximum children: " + maxchildren + System.lineSeparator());
            sb.append("Fragments: " + fragments + System.lineSeparator());
            sb.append("Avg. Fragment size: " + df.format(getAvgFragmentSize()) + System.lineSeparator());
        }

        String[][] absolute = new String[6][7];
        String[][] relative = new String[6][7];
        String[] csvHead = new String[36];
        String[] csv = new String[36];
        ;
        int[] sum = new int[5];
        int i = 0;
        int j = 0;

        for (String key : new TreeSet<>((diffstats.keySet()))) {
            StatsElement s = diffstats.get(key);
            int nodes = s.getElements();
            int matched = s.getMatches();
            int changed = s.getChanges();
            int added = s.getAdded();
            int removed = s.getDeleted();
            int conflicts = s.getConflicting();

            if (i > 0) {
                sum[0] += nodes;
                sum[1] += matched;
                sum[2] += changed;
                sum[3] += added;
                sum[4] += removed;
            }

            String name = key.toLowerCase();
            if (name.endsWith("ss")) {
                name = name + "es";
            } else {
                name = name + "s";
            }

            absolute[i][0] = name;
            absolute[i][1] = String.valueOf(nodes);
            absolute[i][2] = String.valueOf(matched);
            absolute[i][3] = String.valueOf(changed);
            absolute[i][4] = String.valueOf(added);
            absolute[i][5] = String.valueOf(removed);
            absolute[i][6] = String.valueOf(conflicts);

            csvHead[j] = name;
            csv[j++] = String.valueOf(nodes);
            csvHead[j] = "matched " + name;
            csv[j++] = String.valueOf(matched);
            csvHead[j] = "changed " + name;
            csv[j++] = String.valueOf(changed);
            csvHead[j] = "added " + name;
            csv[j++] = String.valueOf(added);
            csvHead[j] = "removed " + name;
            csv[j++] = String.valueOf(removed);
            csvHead[j] = "conflicting " + name;
            csv[j++] = String.valueOf(conflicts);

            if (nodes > 0) {
                relative[i][0] = key.toLowerCase();
                relative[i][1] = df.format(100.0);
                relative[i][2] = df.format(100.0 * matched / nodes);
                relative[i][3] = df.format(100.0 * changed / nodes);
                relative[i][4] = df.format(100.0 * added / nodes);
                relative[i][5] = df.format(100.0 * removed / nodes);
                relative[i][6] = df.format(100.0 * conflicts / nodes);
            } else {
                relative[i][0] = key.toLowerCase();
                relative[i][1] = "null";
                relative[i][2] = "null";
                relative[i][3] = "null";
                relative[i][4] = "null";
                relative[i][5] = "null";
                relative[i][6] = "null";
            }

            i++;
        }

        // CSV
        sb.append(StringUtils.join(csvHead, ';'));
        sb.append(System.lineSeparator());
        sb.append(StringUtils.join(csv, ';'));

        return sb.toString();
    }
}