Skip to content

Commit

Permalink
WIP Use Lookup Table to Associate ComparisonFileName to SubmissionFil…
Browse files Browse the repository at this point in the history
…eNames
  • Loading branch information
nestabentum committed Aug 6, 2022
1 parent ae5a159 commit 3416e17
Show file tree
Hide file tree
Showing 12 changed files with 211 additions and 246 deletions.
3 changes: 2 additions & 1 deletion jplag.cli/src/main/java/de/jplag/CLI.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ public static void main(String[] args) {
JPlag program = new JPlag(options);
logger.info("JPlag initialized");
JPlagResult result = program.run();
ReportObjectFactory.createAndSaveReport(result, arguments.getString(RESULT_FOLDER.flagWithoutDash()));
ReportObjectFactory reportObjectFactory = new ReportObjectFactory();
reportObjectFactory.createAndSaveReport(result, arguments.getString(RESULT_FOLDER.flagWithoutDash()));

} catch (ExitException exception) {
logger.error(exception.getMessage(), exception);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,73 @@
package de.jplag.reporting.reportobject.mapper;
package de.jplag.reporting.jsonfactory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

import de.jplag.*;
import de.jplag.reporting.jsonfactory.FileWriter;
import de.jplag.reporting.reportobject.model.ComparisonReport;
import de.jplag.reporting.reportobject.model.Match;

public class ComparisonReportMapper {
public class ComparisonReportWriter {

private static final FileWriter FILE_WRITER = new FileWriter();
private final Function<Submission, String> submissionToIdFunction;
private final Map<String, Map<String, String>> submissionIdToComparisonFileName = new HashMap<>();

public ComparisonReportWriter(Function<Submission, String> submissionToIdFunction) {
this.submissionToIdFunction = submissionToIdFunction;
}

/**
* Generates detailed ComparisonReport DTO for each comparison in a JPlagResult.
* @param jPlagResult The JPlagResult to generate the comparison reports from. contains information about a comparison
* between two submission. The JPlagResult is used to extract the information on matches between two submissions.
* @return
*/
public void writeComparisonReports(JPlagResult jPlagResult, String path) {
public Map<String, Map<String, String>> writeComparisonReports(JPlagResult jPlagResult, String path) {
int numberOfComparisons = jPlagResult.getOptions().getMaximumNumberOfComparisons();
List<JPlagComparison> comparisons = jPlagResult.getComparisons(numberOfComparisons);
writeComparisons(jPlagResult, path, comparisons);
return submissionIdToComparisonFileName;
}

private void writeComparisons(JPlagResult jPlagResult, String path, List<JPlagComparison> comparisons) {
for (JPlagComparison comparison : comparisons) {
String firstSubmissionId = comparison.getFirstSubmission().getNameSanitized();
String secondSubmissionId = comparison.getSecondSubmission().getNameSanitized();
String firstSubmissionId = getId(comparison.getFirstSubmission());
String secondSubmissionId = getId(comparison.getSecondSubmission());
String fileName = generateComparisonName(firstSubmissionId, secondSubmissionId);
addToLookUp(firstSubmissionId, secondSubmissionId, fileName);
var comparisonReport = new ComparisonReport(firstSubmissionId, secondSubmissionId, comparison.similarity(),
convertMatchesToReportMatches(jPlagResult, comparison));
String fileName = comparisonReport.firstSubmissionId().concat("-").concat(comparisonReport.secondSubmissionId()).concat(".json");
FILE_WRITER.saveAsJSON(comparisonReport, path, fileName);
}
}

private void addToLookUp(String firstSubmissionId, String secondSubmissionId, String fileName) {
writeToMap(secondSubmissionId, firstSubmissionId, fileName);
writeToMap(firstSubmissionId, secondSubmissionId, fileName);
}

private void writeToMap(String id1, String id2, String comparisonFileName) {
if (submissionIdToComparisonFileName.containsKey(id1)) {
submissionIdToComparisonFileName.get(id1).put(id2, comparisonFileName);
} else {
HashMap<String, String> map = new HashMap<>();
map.put(id2, comparisonFileName);
submissionIdToComparisonFileName.put(id1, map);
}
}

private String generateComparisonName(String firstSubmissionId, String secondSubmissionId) {
return firstSubmissionId.concat("-").concat(secondSubmissionId).concat(".json");

}

private String getId(Submission submission) {
return submissionToIdFunction.apply(submission);
}

private List<Match> convertMatchesToReportMatches(JPlagResult result, JPlagComparison comparison) {
return comparison.getMatches().stream()
.map(match -> convertMatchToReportMatch(comparison, match, result.getOptions().getLanguage().supportsColumns())).toList();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package de.jplag.reporting.jsonfactory;

import java.io.File;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DirectoryCreator {
private static final Logger logger = LoggerFactory.getLogger(DirectoryCreator.class);

public static File createDirectory(String path, String name) {
File directory = new File(path.concat("/").concat(name));
if (!directory.exists() && !directory.mkdirs()) {
logger.error("Failed to create dir.");
}
return directory;
}

public static void createDirectory(String path) {
createDirectory(path, "");
}
}
Original file line number Diff line number Diff line change
@@ -1,95 +1,97 @@
package de.jplag.reporting.reportobject;

import static de.jplag.reporting.jsonfactory.DirectoryCreator.createDirectory;
import static de.jplag.reporting.reportobject.mapper.SubmissionNameToIdMapper.buildSubmissionNameToIdMap;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import de.jplag.reporting.reportobject.model.SubmissionName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.jplag.JPlagComparison;
import de.jplag.JPlagResult;
import de.jplag.Submission;
import de.jplag.reporting.jsonfactory.ComparisonReportWriter;
import de.jplag.reporting.jsonfactory.FileWriter;
import de.jplag.reporting.reportobject.mapper.ClusteringResultMapper;
import de.jplag.reporting.reportobject.mapper.ComparisonReportMapper;
import de.jplag.reporting.reportobject.mapper.MetricMapper;
import de.jplag.reporting.reportobject.model.Metric;
import de.jplag.reporting.reportobject.model.OverviewReport;

import static de.jplag.reporting.reportobject.mapper.SubmissionNameMapper.submissionNameOf;

/**
* Factory class, responsible for converting a JPlagResult object to Overview and Comparison DTO classes.
*/
public class ReportObjectFactory {
private static final Logger logger = LoggerFactory.getLogger(ReportObjectFactory.class);

private static final ClusteringResultMapper clusteringResultMapper = new ClusteringResultMapper();
private static final MetricMapper metricMapper = new MetricMapper();
private static final ComparisonReportMapper comparisonReportMapper = new ComparisonReportMapper();
private static final FileWriter fileWriter = new FileWriter();
public static final String OVERVIEW_FILE_NAME = "overview.json";
public static final String SUBMISSIONS_FOLDER = "submissions";
private Map<String, String> submissionNameToIdMap;
private Function<Submission, String> submissionToIdFunction;
private Map<String, Map<String, String>> submissionNameToNameToComparisonFileName;

/**
* @param result The JPlagResult to be converted into a report.
* @param path The Path to save the report to
*/
public static void createAndSaveReport(JPlagResult result, String path) {
public void createAndSaveReport(JPlagResult result, String path) {
createDirectory(path);
writeOverview(result, path);
copySubmissionFilesToReport(path, result);
comparisonReportMapper.writeComparisonReports(result, path);

buildSubmissionToIdMap(result);

writeComparisons(result, path);
writeOverview(result, path);

}

private static File createDirectory(String path, String name) {
File directory = new File(path.concat("/").concat(name));
if (!directory.exists() && !directory.mkdirs()) {
logger.error("Failed to create dir.");
}
return directory;
private void writeComparisons(JPlagResult result, String path) {
ComparisonReportWriter comparisonReportWriter = new ComparisonReportWriter(submissionToIdFunction);
submissionNameToNameToComparisonFileName = comparisonReportWriter.writeComparisonReports(result, path);
}

private static void createDirectory(String path) {
createDirectory(path, "");
private void buildSubmissionToIdMap(JPlagResult result) {
submissionNameToIdMap = buildSubmissionNameToIdMap(result);
submissionToIdFunction = (Submission submission) -> submissionNameToIdMap.get(submission.getName());
}

private static void writeOverview(JPlagResult result, String path) {
List<JPlagComparison> comparisons = getComparisons(result);
OverviewReport overviewReport = new OverviewReport();
private void writeOverview(JPlagResult result, String path) {

// TODO: Consider to treat entries that were checked differently from old entries with prior work.
List<String> folders = new ArrayList<>();
folders.addAll(result.getOptions().getSubmissionDirectories());
folders.addAll(result.getOptions().getOldSubmissionDirectories());
overviewReport.setSubmissionFolderPath(folders);

String baseCodePath = result.getOptions().hasBaseCode() ? result.getOptions().getBaseCodeSubmissionName().orElse("") : "";
overviewReport.setBaseCodeFolderPath(baseCodePath);

overviewReport.setLanguage(result.getOptions().getLanguage().getName());
overviewReport.setFileExtensions(List.of(result.getOptions().getFileSuffixes()));
overviewReport.setSubmissionIds(extractSubmissionNames(comparisons));
overviewReport.setFailedSubmissionNames(List.of()); // No number of failed submissions
overviewReport.setExcludedFiles(result.getOptions().getExcludedFiles());
overviewReport.setMatchSensitivity(result.getOptions().getMinimumTokenMatch());
overviewReport.setDateOfExecution(getDate());
overviewReport.setExecutionTime(result.getDuration());
overviewReport.setComparisonNames(getComparisonNames(comparisons));
overviewReport.setMetrics(getMetrics(result));
overviewReport.setClusters(clusteringResultMapper.map(result));
ClusteringResultMapper clusteringResultMapper = new ClusteringResultMapper(submissionToIdFunction);

OverviewReport overviewReport = new OverviewReport(folders, // submissionFolderPath
baseCodePath, // baseCodeFolderPath
result.getOptions().getLanguage().getName(), // language
List.of(result.getOptions().getFileSuffixes()), // fileExtensions
submissionNameToIdMap, // submissionIds
submissionNameToNameToComparisonFileName, // result.getOptions().getMinimumTokenMatch(),
List.of(), // failedSubmissionNames
result.getOptions().getExcludedFiles(), // excludedFiles
result.getOptions().getMinimumTokenMatch(), // matchSensitivity
getDate(),// dateOfExecution
result.getDuration(), // executionTime
getComparisonNames(submissionNameToNameToComparisonFileName), // comparisonNames
getMetrics(result),// metrics
clusteringResultMapper.map(result)); // clusters

fileWriter.saveAsJSON(overviewReport, path, OVERVIEW_FILE_NAME);

}

private static void copySubmissionFilesToReport(String path, JPlagResult result) {
private void copySubmissionFilesToReport(String path, JPlagResult result) {
List<JPlagComparison> comparisons = result.getComparisons(result.getOptions().getMaximumNumberOfComparisons());
var submissions = getSubmissions(comparisons);
var submissionsPath = createDirectory(path, SUBMISSIONS_FOLDER);
Expand All @@ -105,54 +107,32 @@ private static void copySubmissionFilesToReport(String path, JPlagResult result)
}
}

private static Set<Submission> getSubmissions(List<JPlagComparison> comparisons) {
private Set<Submission> getSubmissions(List<JPlagComparison> comparisons) {
var submissions = comparisons.stream().map(JPlagComparison::getFirstSubmission).collect(Collectors.toSet());
Set<Submission> secondSubmissions = comparisons.stream().map(JPlagComparison::getSecondSubmission).collect(Collectors.toSet());
submissions.addAll(secondSubmissions);
return submissions;
}

private static List<JPlagComparison> getComparisons(JPlagResult result) {
int numberOfComparisons = result.getOptions().getMaximumNumberOfComparisons();
return result.getComparisons(numberOfComparisons);
}

/**
* Gets the names of all submissions.
* @return A list containing all submission names.
*/
private static List<SubmissionName> extractSubmissionNames(List<JPlagComparison> comparisons) {
HashSet<SubmissionName> names = new HashSet<>();
comparisons.forEach(comparison -> {
names.add(submissionNameOf(comparison.getFirstSubmission()));
names.add(submissionNameOf(comparison.getSecondSubmission()));
});
return new ArrayList<>(names);
}



/**
* Gets the names of all comparison.
* @return A list containing all comparisons.
*/
private static List<String> getComparisonNames(List<JPlagComparison> comparisons) {
List<String> names = new ArrayList<>();
comparisons.forEach(comparison -> names
.add(String.join("-", comparison.getFirstSubmission().getNameSanitized(), comparison.getSecondSubmission().getNameSanitized())));
return names;
private Collection<String> getComparisonNames(Map<String, Map<String, String>> submissionNameToNameToComparisonFileName) {
return submissionNameToNameToComparisonFileName.values().stream().flatMap(map -> map.values().stream()).collect(Collectors.toSet());
}

/**
* Gets the used metrics in a JPlag comparison. As Max Metric is included in every JPlag run, this always include Max
* Metric.
* @return A list contains Metric DTOs.
*/
private static List<Metric> getMetrics(JPlagResult result) {
private List<Metric> getMetrics(JPlagResult result) {
MetricMapper metricMapper = new MetricMapper(submissionToIdFunction);
return List.of(metricMapper.getAverageMetric(result), metricMapper.getMaxMetric(result));
}

private static String getDate() {
private String getDate() {
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yy");
Date date = new Date();
return dateFormat.format(date);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.Collection;
import java.util.List;
import java.util.function.Function;

import de.jplag.JPlagResult;
import de.jplag.Submission;
Expand All @@ -12,6 +13,12 @@
* Extracts and maps the clusters from the JPlagResult to the corresponding JSON DTO
*/
public class ClusteringResultMapper {
private final Function<Submission, String> submissionToIdFunction;

public ClusteringResultMapper(Function<Submission, String> submissionToIdFunction) {
this.submissionToIdFunction = submissionToIdFunction;
}

public List<Cluster> map(JPlagResult result) {
var clusteringResult = result.getClusteringResult();
return clusteringResult.stream().map(ClusteringResult::getClusters).flatMap(Collection::stream).map(this::convertCluster).toList();
Expand All @@ -20,7 +27,7 @@ public List<Cluster> map(JPlagResult result) {
private Cluster convertCluster(de.jplag.clustering.Cluster<Submission> from) {
var strength = from.getCommunityStrength();
var avgSimilarity = from.getAverageSimilarity();
var member = from.getMembers().stream().map(Submission::getNameSanitized).toList();
var member = from.getMembers().stream().map(submissionToIdFunction).toList();
return new Cluster(avgSimilarity, strength, member);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import de.jplag.JPlagComparison;
import de.jplag.JPlagResult;
import de.jplag.Messages;
import de.jplag.Submission;
import de.jplag.options.SimilarityMetric;
import de.jplag.reporting.reportobject.model.Metric;
import de.jplag.reporting.reportobject.model.TopComparison;
Expand All @@ -17,6 +18,12 @@
* Extracts and maps metrics from the JPlagResult to the corresponding JSON DTO
*/
public class MetricMapper {
private final Function<Submission, String> submissionToIdFunction;

public MetricMapper(Function<Submission, String> submissionToIdFunction) {
this.submissionToIdFunction = submissionToIdFunction;
}

public Metric getAverageMetric(JPlagResult result) {
return new Metric(SimilarityMetric.AVG.name(), intArrayToList(result.getSimilarityDistribution()), getTopComparisons(getComparisons(result)),
Messages.getString("SimilarityMetric.Avg.Description"));
Expand All @@ -32,22 +39,22 @@ private List<JPlagComparison> getComparisons(JPlagResult result) {
return result.getComparisons(maxNumberOfComparisons);
}

private static List<Integer> intArrayToList(int[] array) {
private List<Integer> intArrayToList(int[] array) {
return Arrays.stream(array).boxed().collect(Collectors.toList());
}

private static List<TopComparison> getTopComparisons(List<JPlagComparison> comparisons, Function<JPlagComparison, Float> similarityExtractor) {
private List<TopComparison> getTopComparisons(List<JPlagComparison> comparisons, Function<JPlagComparison, Float> similarityExtractor) {
return comparisons.stream().sorted(Comparator.comparing(similarityExtractor).reversed())
.map(comparison -> new TopComparison(comparison.getFirstSubmission().getNameSanitized(),
comparison.getSecondSubmission().getNameSanitized(), similarityExtractor.apply(comparison)))
.map(comparison -> new TopComparison(submissionToIdFunction.apply(comparison.getFirstSubmission()),
submissionToIdFunction.apply(comparison.getSecondSubmission()), similarityExtractor.apply(comparison)))
.toList();
}

private static List<TopComparison> getTopComparisons(List<JPlagComparison> comparisons) {
private List<TopComparison> getTopComparisons(List<JPlagComparison> comparisons) {
return getTopComparisons(comparisons, JPlagComparison::similarity);
}

private static List<TopComparison> getMaxSimilarityTopComparisons(List<JPlagComparison> comparisons) {
private List<TopComparison> getMaxSimilarityTopComparisons(List<JPlagComparison> comparisons) {
return getTopComparisons(comparisons, JPlagComparison::maximalSimilarity);
}

Expand Down
Loading

0 comments on commit 3416e17

Please sign in to comment.