Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zip Report Viewer Files #588

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
@@ -0,0 +1,111 @@
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.reportobject.model.ComparisonReport;
import de.jplag.reporting.reportobject.model.Match;

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 and writes them to the disk as json
* files.
* @param jPlagResult The JPlagResult to generate the comparison reports from. contains information about a comparison
* @param path The path to write the comparison files to
* @return Nested map that associates each pair of submissions (by their ids) to their comparison file name. The
* comparison file name for submission with id id1 and id2 can be fetched by executing get two times:
* map.get(id1).get(id2). The nested map is symmetrical therefore, both map.get(id1).get(id2) and map.get(id2).get(id1)
* yield the same result.
*/
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 = submissionToIdFunction.apply(comparison.getFirstSubmission());
String secondSubmissionId = submissionToIdFunction.apply(comparison.getSecondSubmission());
String fileName = generateComparisonName(firstSubmissionId, secondSubmissionId);
addToLookUp(firstSubmissionId, secondSubmissionId, fileName);
var comparisonReport = new ComparisonReport(firstSubmissionId, secondSubmissionId, comparison.similarity(),
convertMatchesToReportMatches(jPlagResult, comparison));
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) {
String name = concatenate(firstSubmissionId, secondSubmissionId);
String finalName = name;
var timesNameAlreadyExists = submissionIdToComparisonFileName.values().stream().filter(map -> map.containsValue(finalName)).count();
if (timesNameAlreadyExists > 0) {
name = concatenate(firstSubmissionId, secondSubmissionId, timesNameAlreadyExists + 1);
}
return name;

}

private String concatenate(String firstSubmissionId, String secondSubmissionId, long index) {
return firstSubmissionId.concat("-").concat(secondSubmissionId).concat(index > 0 ? "-" + index : "").concat(".json");
}

private String concatenate(String firstSubmissionId, String secondSubmissionId) {
return concatenate(firstSubmissionId, secondSubmissionId, 0);
}

private List<Match> convertMatchesToReportMatches(JPlagResult result, JPlagComparison comparison) {
return comparison.getMatches().stream()
.map(match -> convertMatchToReportMatch(comparison, match, result.getOptions().getLanguage().supportsColumns())).toList();
}

private Match convertMatchToReportMatch(JPlagComparison comparison, de.jplag.Match match, boolean languageSupportsColumnsAndLines) {
TokenList tokensFirst = comparison.getFirstSubmission().getTokenList();
TokenList tokensSecond = comparison.getSecondSubmission().getTokenList();
Token startTokenFirst = tokensFirst.getToken(match.startOfFirst());
Token endTokenFirst = tokensFirst.getToken(match.startOfFirst() + match.length() - 1);
Token startTokenSecond = tokensSecond.getToken(match.startOfSecond());
Token endTokenSecond = tokensSecond.getToken(match.startOfSecond() + match.length() - 1);

int startFirst = getPosition(languageSupportsColumnsAndLines, startTokenFirst);
int endFirst = getPosition(languageSupportsColumnsAndLines, endTokenFirst);
int startSecond = getPosition(languageSupportsColumnsAndLines, startTokenSecond);
int endSecond = getPosition(languageSupportsColumnsAndLines, endTokenSecond);
int tokens = match.length();

return new Match(startTokenFirst.getFile(), startTokenSecond.getFile(), startFirst, endFirst, startSecond, endSecond, tokens);
}

private int getPosition(boolean languageSupportsColumnsAndLines, Token token) {
return languageSupportsColumnsAndLines ? token.getLine() : token.getIndex();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package de.jplag.reporting.jsonfactory;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Comparator;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

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

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

/**
* Creates a directory.
* @param path The path under which the new directory ought to be created
* @param name The name of the new directory
* @return The created directory
*/
public static File createDirectory(String path, String name) throws IOException {
File directory = new File(path.concat("/").concat(name));
if (!directory.exists() && !directory.mkdirs()) {
throw new IOException("Failed to create dir.");
}
return directory;
}

/**
* Create a directory with the given path
* @param path The path of the new directory
*/
public static void createDirectory(String path) throws IOException {
createDirectory(path, "");
}

/**
* Delete the directory and all of its contents, identified by the given path
* @param path The path that identifies the directory to delete
*/
public static void deleteDirectory(String path) {
try (var f = Files.walk(Path.of(path))) {
f.sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
} catch (IOException e) {
logger.error("Could not delete folder " + path, e);
}
}

/**
* Zip the directory identified by the given path
* @param path The path that identifies the directory to zip
* @return True if zip was successful, false otherwise
*/
public static boolean zipDirectory(String path) {
Path p = Path.of(path);
String zipName = path + ".zip";

try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipName))) {

Files.walkFileTree(p, new SimpleFileVisitor<>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Path targetFile = p.relativize(file);
zos.putNextEntry(new ZipEntry(targetFile.toString()));

byte[] bytes = Files.readAllBytes(file);
zos.write(bytes, 0, bytes.length);
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
logger.error("Unable to zip " + file, exc);
return FileVisitResult.CONTINUE;
}
});
} catch (IOException e) {
return false;
nestabentum marked this conversation as resolved.
Show resolved Hide resolved
}
JanWittler marked this conversation as resolved.
Show resolved Hide resolved
return true;
}
}
Loading