Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
de.dagere.peass.analysis.properties.PropertyReadHelper Maven / Gradle / Ivy
package de.dagere.peass.analysis.properties;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import de.dagere.peass.analysis.changes.Change;
import de.dagere.peass.analysis.properties.ChangeProperty.TraceChange;
import de.dagere.peass.config.ExecutionConfig;
import de.dagere.peass.dependency.ChangeManager;
import de.dagere.peass.dependency.analysis.data.ChangedEntity;
import de.dagere.peass.dependency.analysis.data.EntityUtil;
import de.dagere.peass.dependency.analysis.data.VersionDiff;
import de.dagere.peass.dependency.changesreading.ClazzChangeData;
import de.dagere.peass.dependency.execution.pom.MavenPomUtil;
import de.dagere.peass.dependency.persistence.ExecutionData;
import de.dagere.peass.dependency.traces.requitur.Sequitur;
import de.dagere.peass.folders.PeassFolders;
import de.dagere.peass.vcs.GitCommit;
import de.dagere.peass.vcs.GitUtils;
import de.dagere.peass.vcs.VersionIteratorGit;
import difflib.Delta;
import difflib.Delta.TYPE;
import difflib.DiffUtils;
import difflib.Patch;
public class PropertyReadHelper {
private static final Logger LOG = LogManager.getLogger(PropertyReadHelper.class);
public static final String keywords[] = { "abstract", "assert", "boolean",
"break", "byte", "case", "catch", "char", "class", "const",
"continue", "default", "do", "double", "else", "extends", "false",
"final", "finally", "float", "for", "goto", "if", "implements",
"import", "instanceof", "int", "interface", "long", "native",
"new", "null", "package", "private", "protected", "public",
"return", "short", "static", "strictfp", "super", "switch",
"synchronized", "this", "throw", "throws", "transient", "true",
"try", "void", "volatile", "while",
"System.out.println", "System.gc", "Thread.sleep" };
private final ExecutionData changedTests;
private final ChangedEntity testClazz;
private final String version, prevVersion;
private final Change change;
private final File projectFolder;
private final File viewFolder;
private final File methodSourceFolder;
/**
* Just for local debugging purposes - no public use intended
*
* @param args
* @throws IOException
*/
public static void main(final String[] args) throws IOException {
final ChangedEntity ce = new ChangedEntity("org.apache.commons.fileupload.StreamingTest", "");
final Change change = new Change();
change.setChangePercent(-8.0);
change.setMethod("testFILEUPLOAD135");
final File projectFolder2 = new File("../../projekte/commons-fileupload");
final File viewFolder2 = new File("/home/reichelt/daten3/diss/repos/preprocessing/4/commons-fileupload/views_commons-fileupload/");
final PropertyReadHelper propertyReadHelper = new PropertyReadHelper("96f8f56556a8592bfed25c82acedeffc4872ac1f",
"09d16c", ce, change, projectFolder2, viewFolder2,
new File("/tmp/"), null);
propertyReadHelper.read();
}
public PropertyReadHelper(final String version, final String prevVersion, final ChangedEntity clazz,
final Change change, final File projectFolder, final File viewFolder, final File methodSourceFolder, final ExecutionData changedTests) {
this.version = version;
this.prevVersion = prevVersion;
if (clazz.getMethod() != null) {
throw new RuntimeException("Method must not be set!");
}
this.testClazz = clazz;
this.change = change;
this.projectFolder = projectFolder;
this.viewFolder = viewFolder;
this.methodSourceFolder = methodSourceFolder;
this.changedTests = changedTests;
}
public ChangeProperty read() throws IOException {
final ChangeProperty property = new ChangeProperty(change);
getSourceInfos(property);
LOG.debug("Comparing " + version + " " + property.getMethod());
final File folder = new File(viewFolder, "view_" + version + File.separator + testClazz + File.separator + property.getMethod());
if (folder.exists()) {
// analyseTraceChange(folder, property);
return property;
} else {
LOG.error("Folder {} does not exist", folder);
return property;
}
}
private String getShortPrevVersion() {
// This happens for the initial version
if (prevVersion == null) {
return "";
}
if (prevVersion.endsWith("~1")) {
return prevVersion.substring(0, 6) + "~1";
} else {
return prevVersion.substring(0, 6);
}
}
public void getSourceInfos(final ChangeProperty property) throws FileNotFoundException, IOException {
final File folder = new File(viewFolder, "view_" + version + File.separator + testClazz + File.separator + property.getMethod());
final File traceFileCurrent = new File(folder, version.substring(0, 6) + "_method");
File traceFileOld = new File(folder, getShortPrevVersion() + "_method");
if (changedTests != null) {
traceFileOld = searchOldTraceFile(property, traceFileOld);
}
if (traceFileCurrent.exists() && traceFileOld.exists()) {
analyzeTraceFiles(property, traceFileCurrent, traceFileOld);
} else {
readExpandedFileTrace(folder);
if (!traceFileCurrent.exists()) {
LOG.error("Tracefile not found: {}", traceFileCurrent);
} else {
LOG.error("Tracefile not found: {}", traceFileOld);
}
}
}
private void readExpandedFileTrace(final File folder) throws IOException, FileNotFoundException {
File expandedFile = new File(folder, version.substring(0, 6) + "_method_expanded");
if (expandedFile.exists()) {
LOG.info("Reading method sources from expanded tracefile {}", expandedFile);
final List traceCurrent = Sequitur.getExpandedTrace(expandedFile);
final PeassFolders folders = new PeassFolders(projectFolder);
// Only to read old sources
getChanges(folders);
readMethodSources(new ChangeProperty(), folders, new HashSet<>(traceCurrent));
}
}
private File searchOldTraceFile(final ChangeProperty property, File traceFileOld) {
List versions = new ArrayList<>(changedTests.getVersions().keySet());
int index = versions.indexOf(prevVersion);
if (index == -1) {
index = versions.indexOf(version) - 1;
}
LOG.debug("Trying old versions starting with {} Versions: {}", index, changedTests.getVersions().keySet());
while (!traceFileOld.exists() && index >= 0) {
String tryVersion = versions.get(index);
File versionFolder = new File(viewFolder, "view_" + tryVersion);
File predecessorFolder = new File(versionFolder, testClazz + File.separator + property.getMethod());
String tryVersionShort = tryVersion.substring(0, 6);
traceFileOld = new File(predecessorFolder, tryVersionShort + "_method");
LOG.debug("Trying file " + traceFileOld.getAbsolutePath());
index--;
}
return traceFileOld;
}
private void analyzeTraceFiles(final ChangeProperty property, final File traceFileCurrent, final File traceFileOld) throws IOException, FileNotFoundException {
final PeassFolders folders = new PeassFolders(projectFolder);
final Map changes = getChanges(folders);
final List traceCurrent = Sequitur.getExpandedTrace(traceFileCurrent);
final List traceOld = Sequitur.getExpandedTrace(traceFileOld);
determineTraceSizeChanges(property, traceCurrent, traceOld);
final Set merged = getMergedCalls(traceCurrent, traceOld);
readMethodSources(property, folders, merged);
identifyAffectedClasses(property, merged);
LOG.info("Calls: " + merged);
getTestSourceAffection(property, merged, folders, changes);
}
private Map getChanges(final PeassFolders folders) {
GitCommit firstCommit = new GitCommit(prevVersion, null, null, null);
List commits = Arrays.asList(new GitCommit[] { new GitCommit(version, null, null, null), firstCommit });
final VersionIteratorGit iterator = new VersionIteratorGit(projectFolder, commits, firstCommit);
final ChangeManager changeManager = new ChangeManager(folders, iterator, new ExecutionConfig());
final Map changes = changeManager.getChanges(prevVersion, version);
return changes;
}
private void readMethodSources(final ChangeProperty property, final PeassFolders folders, final Set merged) throws FileNotFoundException, IOException {
for (final String calledInOneMethod : merged) {
LOG.debug("Loading: " + calledInOneMethod);
final ChangedEntity entity = EntityUtil.determineEntity(calledInOneMethod);
final MethodChangeReader reader = new MethodChangeReader(methodSourceFolder, folders.getProjectFolder(), folders.getOldSources(), entity, version);
reader.readMethodChangeData();
getKeywordChanges(property, reader, entity);
}
}
private void identifyAffectedClasses(final ChangeProperty property, final Set calls) throws FileNotFoundException, IOException {
try {
List modules = MavenPomUtil.getGenericModules(projectFolder, new ExecutionConfig()).getModules();
final VersionDiff diff = GitUtils.getChangedFiles(projectFolder, modules, version);
removeUncalledClasses(calls, diff);
property.setAffectedClasses(diff.getChangedClasses().size());
final int changedLines = GitUtils.getChangedLines(projectFolder, version, diff.getChangedClasses());
property.setAffectedLines(changedLines);
} catch (final XmlPullParserException e) {
e.printStackTrace();
}
}
private void removeUncalledClasses(final Set calls, final VersionDiff diff) {
for (final Iterator it = diff.getChangedClasses().iterator(); it.hasNext();) {
final ChangedEntity entity = it.next();
boolean called = false;
for (final String call : calls) {
if (call.startsWith(entity.getJavaClazzName())) {
called = true;
break;
}
}
if (!called)
it.remove();
}
}
public void getKeywordChanges(final ChangeProperty property, final MethodChangeReader changeManager, final ChangedEntity entity) throws FileNotFoundException {
final Patch patch = changeManager.getKeywordChanges(entity);
final Map vNewkeywords = new HashMap<>();
final Map vOldkeywords = new HashMap<>();
for (final Delta changeSet : patch.getDeltas()) {
for (final String line : changeSet.getOriginal().getLines()) {
getKeywordCount(vOldkeywords, line);
}
for (final String line : changeSet.getRevised().getLines()) {
getKeywordCount(vNewkeywords, line);
}
}
for (final Map.Entry vNew : vNewkeywords.entrySet()) {
property.getAddedMap().put(vNew.getKey(), vNew.getValue());
}
for (final Map.Entry vOld : vOldkeywords.entrySet()) {
// System.out.println("Removed: " + v2.getKey() + " " + v2.getValue());
property.getRemovedMap().put(vOld.getKey(), vOld.getValue());
}
}
public Set getMergedCalls(final List traceCurrent, final List traceOld) {
final Set merged = new HashSet<>();
final Set calledCurrent = new HashSet<>(traceCurrent);
final Set calledOld = new HashSet<>(traceOld);
merged.addAll(calledCurrent);
merged.addAll(calledOld);
// intersection.retainAll(calledOld);
return merged;
}
void getTestSourceAffection(final ChangeProperty property, final Set calls, final PeassFolders folders, final Map changes)
throws FileNotFoundException {
final ClazzChangeData clazzChangeData = changes.get(testClazz);
if (clazzChangeData != null) {
if (clazzChangeData.isOnlyMethodChange()) {
for (final Set methodsOfClazz : clazzChangeData.getChangedMethods().values()) {
if (methodsOfClazz.contains(property.getMethod())) {
property.setAffectsTestSource(true);
}
}
} else {
property.setAffectsTestSource(true);
}
}
// Prinzipiell: Man müsste schauen, wo der Quelltext liegt, nicht, wie er heißt..
for (final Entry changedEntity : changes.entrySet()) {
// final Set guessedTypes = new PropertyChangeGuesser().getGuesses(folders, changedEntity);
// property.getGuessedTypes().addAll(guessedTypes);
final ChangedEntity outerClazz = changedEntity.getKey();
if (!changedEntity.getValue().isOnlyMethodChange()) {
for (final String call : calls) {
final String clazzCall = call.substring(0, call.indexOf("#"));
if (outerClazz.getJavaClazzName().equals(clazzCall)) {
processFoundCall(property, changedEntity);
}
}
} else {
for (final Map.Entry> changedClazz : changedEntity.getValue().getChangedMethods().entrySet()) {
for (final String changedMethod : changedClazz.getValue()) {
String fqn;
if (changedMethod.contains(ChangedEntity.METHOD_SEPARATOR)) {
fqn = outerClazz.getPackage() + "." + changedClazz.getKey() + ChangedEntity.CLAZZ_SEPARATOR + changedMethod;
} else {
fqn = outerClazz.getPackage() + "." + changedClazz.getKey() + ChangedEntity.METHOD_SEPARATOR + changedMethod;
}
if (fqn.contains("(") && changedClazz.getKey().contains(ChangedEntity.CLAZZ_SEPARATOR)) {
final String innerParameter = changedClazz.getKey().substring(0, changedClazz.getKey().lastIndexOf(ChangedEntity.CLAZZ_SEPARATOR));
fqn = fqn.substring(0, fqn.indexOf("(") + 1) + innerParameter + "," + fqn.substring(fqn.indexOf("(") + 1);
}
if (calls.contains(fqn)) {
processFoundCall(property, changedEntity);
}
}
}
}
}
}
/**
* Determines how the trace has changed viewed from trace1, e.g. ADDED_CALLS means that trace2 has more calls than trace1.
*
* @param property
* @param traceCurrent
* @param traceOld
* @throws IOException
*/
public static void determineTraceSizeChanges(final ChangeProperty property, final List traceCurrent, final List traceOld) throws IOException {
LOG.debug("Trace sizes: {}, {}", traceCurrent.size(), traceOld.size());
if (traceCurrent.size() + traceOld.size() < 10000) {
final Patch patch = DiffUtils.diff(traceOld, traceCurrent);
LOG.debug(patch);
int added = 0, removed = 0;
for (final Delta delta : patch.getDeltas()) {
if (delta.getType().equals(TYPE.DELETE)) {
removed++;
} else if (delta.getType().equals(TYPE.INSERT)) {
added++;
} else if (delta.getType().equals(TYPE.CHANGE)) {
added++;
removed++;
}
}
if (added > 0 && removed > 0) {
property.setTraceChangeType(TraceChange.BOTH);
} else if (added > 0) {
property.setTraceChangeType(TraceChange.ADDED_CALLS);
} else if (removed > 0) {
property.setTraceChangeType(TraceChange.REMOVED_CALLS);
} else {
property.setTraceChangeType(TraceChange.NO_CALL_CHANGE);
}
} else {
property.setTraceChangeType(TraceChange.UNKNOWN);
}
property.setCalls(traceCurrent.size());
property.setCallsOld(traceOld.size());
}
private void processFoundCall(final ChangeProperty property, final Entry changedEntity) {
final ChangedEntity call = changedEntity.getKey();
if (call.getClazz().toLowerCase().contains("test")) {
property.setAffectsTestSource(true);
} else {
property.setAffectsSource(true);
}
final String packageName = call.getPackage();
for (final Map.Entry> methods : changedEntity.getValue().getChangedMethods().entrySet()) {
if (methods.getValue() != null && methods.getValue().size() > 0) {
for (final String method : methods.getValue()) {
property.getAffectedMethods().add(packageName + "." + methods.getKey() + ChangedEntity.METHOD_SEPARATOR + method);
}
} else {
property.getAffectedMethods().add(call.getJavaClazzName());
}
}
}
private static void getKeywordCount(final Map v1keywords, final String line) {
for (final String keyword : keywords) {
if (line.contains(keyword)) {
final Integer integer = v1keywords.get(keyword);
final int count = integer != null ? integer : 0;
v1keywords.put(keyword, count + 1);
}
}
}
}