From 4265441490bb0b4dd50e3f212a6cd90782fc754f Mon Sep 17 00:00:00 2001 From: Anton Romanov Date: Mon, 12 Apr 2021 10:41:26 +0400 Subject: [PATCH] #12 -- Get file content for specific commit --- .../api/StructuralUnitIdentifier.java | 16 ++++--- .../controller/StructuralUnitController.java | 10 ++++- .../heuristic/service/JavaIdentifier.java | 43 +++++++++++++++++-- .../service/StructuralUnitService.java | 32 ++++++++------ .../ru/ulstu/extractor/model/FileChange.java | 16 +++++++ .../service/GitRepositoryService.java | 35 ++++++++++++++- 6 files changed, 124 insertions(+), 28 deletions(-) diff --git a/src/main/java/ru/ulstu/extractor/heuristic/api/StructuralUnitIdentifier.java b/src/main/java/ru/ulstu/extractor/heuristic/api/StructuralUnitIdentifier.java index 104f95d..5956542 100644 --- a/src/main/java/ru/ulstu/extractor/heuristic/api/StructuralUnitIdentifier.java +++ b/src/main/java/ru/ulstu/extractor/heuristic/api/StructuralUnitIdentifier.java @@ -29,18 +29,24 @@ public abstract class StructuralUnitIdentifier { return getEntityClasses(projectPath, subDirectory, projectFiles); } + public abstract boolean canAppliedToCode(String sourceCode); + + public abstract boolean canAppliedToFile(File projectFile); + + public abstract boolean canAppliedToProject(String projectPath, List projectFiles, List rootProjectFiles); + public abstract boolean isEntityClass(File file); + public abstract boolean isEntityClass(String sourceCode); + + protected abstract boolean isBusinessLogicClass(File file); + public abstract List getBusinessLogicClasses(); public abstract boolean isMultiModuleProject(); public abstract Optional getBuildTool(List rootDirectoryFiles); - public abstract boolean canAppliedToProject(String projectPath, List projectFiles, List rootProjectFiles); - - public abstract boolean canAppliedToFile(File projectFile); - protected abstract List getEntityClasses(String projectPath, String subDirectory, List projectFiles); protected abstract String getSourceDirectory(List rootProjectFiles); @@ -51,8 +57,6 @@ public abstract class StructuralUnitIdentifier { protected abstract ProgrammingLanguage getProgrammingLanguage(); - protected abstract boolean isBusinessLogicClass(File file); - protected Optional getMainProgrammingLanguage(String projectPath, List projectFiles, List rootProjectFiles) { String subDirectory = getSourceDirectory(rootProjectFiles); Map projectFileLanguageFrequency = new HashMap<>(); diff --git a/src/main/java/ru/ulstu/extractor/heuristic/controller/StructuralUnitController.java b/src/main/java/ru/ulstu/extractor/heuristic/controller/StructuralUnitController.java index 96b9e14..ff9b7fa 100644 --- a/src/main/java/ru/ulstu/extractor/heuristic/controller/StructuralUnitController.java +++ b/src/main/java/ru/ulstu/extractor/heuristic/controller/StructuralUnitController.java @@ -10,7 +10,9 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import ru.ulstu.extractor.heuristic.model.StructuralUnit; import ru.ulstu.extractor.heuristic.service.StructuralUnitService; +import ru.ulstu.extractor.service.GitRepositoryService; +import java.io.File; import java.io.IOException; import java.util.List; @@ -18,13 +20,17 @@ import java.util.List; @RequestMapping("StructuralUnitController") public class StructuralUnitController { private final StructuralUnitService structuralUnitService; + private final GitRepositoryService gitRepositoryService; - public StructuralUnitController(StructuralUnitService structuralUnitService) { + public StructuralUnitController(StructuralUnitService structuralUnitService, + GitRepositoryService gitRepositoryService) { this.structuralUnitService = structuralUnitService; + this.gitRepositoryService = gitRepositoryService; } @GetMapping("get-entities") public List getEntities(String repositoryUrl) throws IOException { - return structuralUnitService.getEntities(repositoryUrl); + File rootPath = gitRepositoryService.getProjectDirectoryFile(repositoryUrl); + return structuralUnitService.getEntities(rootPath); } } diff --git a/src/main/java/ru/ulstu/extractor/heuristic/service/JavaIdentifier.java b/src/main/java/ru/ulstu/extractor/heuristic/service/JavaIdentifier.java index 1168172..438ed33 100644 --- a/src/main/java/ru/ulstu/extractor/heuristic/service/JavaIdentifier.java +++ b/src/main/java/ru/ulstu/extractor/heuristic/service/JavaIdentifier.java @@ -18,7 +18,8 @@ import ru.ulstu.extractor.heuristic.model.StructuralUnit; import ru.ulstu.extractor.util.StringUtils; import java.io.File; -import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Files; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -27,6 +28,7 @@ import static ru.ulstu.extractor.heuristic.service.DetectorService.LangDetectScr @Service public class JavaIdentifier extends StructuralUnitIdentifier { + private static final String ENTITY_ANNOTATION = "@Entity"; private final DetectorService detectorService; private final BuildToolService buildToolService; private final ProgrammingLanguageService programmingLanguageService; @@ -49,6 +51,10 @@ public class JavaIdentifier extends StructuralUnitIdentifier { return getMainProgrammingLanguage(projectFile, LOW).orElse(null) instanceof JavaProgrammingLanguage; } + public boolean canAppliedToCode(String sourceCode) { + return getMainProgrammingLanguage(sourceCode).orElse(null) instanceof JavaProgrammingLanguage; + } + @Override public List getEntityClasses(String projectPath, String subDirectory, List projectFiles) { return projectFiles.stream() @@ -58,6 +64,12 @@ public class JavaIdentifier extends StructuralUnitIdentifier { .collect(Collectors.toList()); } + protected Optional getMainProgrammingLanguage(String sourceCode) { + return sourceCodeContainsClass(sourceCode) + ? Optional.of(getProgrammingLanguage()) + : Optional.empty(); + } + @Override public List getBusinessLogicClasses() { return null; @@ -91,16 +103,30 @@ public class JavaIdentifier extends StructuralUnitIdentifier { @Override public boolean isEntityClass(File file) { try { - return file.getName().endsWith("java") && classContainsAnnotation(file, "@Entity"); + return file.getName().endsWith("java") && classContainsAnnotation(file, ENTITY_ANNOTATION); + } catch (Exception ex) { + ex.printStackTrace(); + } + return false; + } + + @Override + public boolean isEntityClass(String sourceCode) { + try { + return classContainsAnnotation(sourceCode, ENTITY_ANNOTATION); } catch (Exception ex) { ex.printStackTrace(); } return false; } - private boolean classContainsAnnotation(File file, String annotationDeclaration) throws FileNotFoundException { + private boolean classContainsAnnotation(File file, String annotationDeclaration) throws IOException { + return classContainsAnnotation(new String(Files.readAllBytes(file.toPath())), annotationDeclaration); + } + + private boolean classContainsAnnotation(String sourceCode, String annotationDeclaration) { JavaParser parser = new JavaParser(); - ParseResult parseResult = parser.parse(file); + ParseResult parseResult = parser.parse(sourceCode); if (parseResult.getResult().isPresent() && parseResult.getResult().get().findCompilationUnit().isPresent()) { return parseResult.getResult().get().getTypes().stream() .anyMatch(clazz -> clazz.getAnnotations().stream().anyMatch(annotation -> annotation.toString().startsWith(annotationDeclaration))); @@ -108,6 +134,15 @@ public class JavaIdentifier extends StructuralUnitIdentifier { return false; } + private boolean sourceCodeContainsClass(String sourceCode) { + JavaParser parser = new JavaParser(); + ParseResult parseResult = parser.parse(sourceCode); + if (parseResult.getResult().isPresent() && parseResult.getResult().get().findCompilationUnit().isPresent()) { + return parseResult.getResult().get().getTypes().stream().findAny().isPresent(); + } + return false; + } + @Override protected String getSourceDirectory(List rootDirectoryFiles) { return buildToolService.getProjectBuildTool(rootDirectoryFiles) diff --git a/src/main/java/ru/ulstu/extractor/heuristic/service/StructuralUnitService.java b/src/main/java/ru/ulstu/extractor/heuristic/service/StructuralUnitService.java index 389ec81..c7bdfcc 100644 --- a/src/main/java/ru/ulstu/extractor/heuristic/service/StructuralUnitService.java +++ b/src/main/java/ru/ulstu/extractor/heuristic/service/StructuralUnitService.java @@ -8,49 +8,53 @@ package ru.ulstu.extractor.heuristic.service; import org.springframework.stereotype.Service; import ru.ulstu.extractor.heuristic.api.StructuralUnitIdentifier; import ru.ulstu.extractor.heuristic.model.StructuralUnit; -import ru.ulstu.extractor.service.GitRepositoryService; import java.io.File; import java.io.IOException; import java.util.List; +import java.util.Optional; import java.util.function.Predicate; @Service public class StructuralUnitService { - private final GitRepositoryService gitRepositoryService; private final DirectoryService directoryService; private final List structuralUnitIdentifiers; - public StructuralUnitService(GitRepositoryService gitRepositoryService, - DirectoryService directoryService, + public StructuralUnitService(DirectoryService directoryService, List structuralUnitIdentifiers) { - this.gitRepositoryService = gitRepositoryService; this.directoryService = directoryService; this.structuralUnitIdentifiers = structuralUnitIdentifiers; } - public List getEntities(String repositoryUrl) throws IOException { - File rootPath = gitRepositoryService.getProjectDirectoryFile(repositoryUrl); + public List getEntities(File rootPath) throws IOException { List projectFiles = directoryService.getFilesRecursively(rootPath); List rootProjectFiles = directoryService.getDirectoryFiles(rootPath.toPath()); return getStructuralUnitIdentifier( structuralUnitIdentifier -> structuralUnitIdentifier.canAppliedToProject( rootPath.getPath(), projectFiles, - rootProjectFiles) - ).getEntityClasses(rootPath.getPath(), projectFiles, rootProjectFiles); + rootProjectFiles)) + .orElseThrow(() -> new RuntimeException("Identifier not found")) + .getEntityClasses(rootPath.getPath(), projectFiles, rootProjectFiles); } public boolean containsEntity(File projectFile) { return getStructuralUnitIdentifier( - structuralUnitIdentifier -> structuralUnitIdentifier.canAppliedToFile(projectFile) - ).isEntityClass(projectFile); + structuralUnitIdentifier -> structuralUnitIdentifier.canAppliedToFile(projectFile)) + .map(identifier -> identifier.isEntityClass(projectFile)) + .orElse(false); } - private StructuralUnitIdentifier getStructuralUnitIdentifier(Predicate predicate) { + public boolean containsEntity(String sourceCode) { + return getStructuralUnitIdentifier( + structuralUnitIdentifier -> structuralUnitIdentifier.canAppliedToCode(sourceCode)) + .map(identifier -> identifier.isEntityClass(sourceCode)) + .orElse(false); + } + + private Optional getStructuralUnitIdentifier(Predicate predicate) { return structuralUnitIdentifiers.stream() .filter(predicate) - .findAny() - .orElseThrow(() -> new RuntimeException("Identifier not found")); + .findAny(); } } diff --git a/src/main/java/ru/ulstu/extractor/model/FileChange.java b/src/main/java/ru/ulstu/extractor/model/FileChange.java index 2493da6..010e4a6 100644 --- a/src/main/java/ru/ulstu/extractor/model/FileChange.java +++ b/src/main/java/ru/ulstu/extractor/model/FileChange.java @@ -1,3 +1,8 @@ +/* + * Copyright (C) 2021 Anton Romanov - All Rights Reserved + * You may use, distribute and modify this code, please write to: romanov73@gmail.com. + */ + package ru.ulstu.extractor.model; import org.hibernate.annotations.Fetch; @@ -20,6 +25,9 @@ public class FileChange extends BaseEntity { @Transient private boolean added; + @Transient + private boolean containsEntity; + @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinColumn(name = "file_change_id", unique = true) @Fetch(FetchMode.SUBSELECT) @@ -71,4 +79,12 @@ public class FileChange extends BaseEntity { public boolean isAdded() { return added; } + + public boolean isContainsEntity() { + return containsEntity; + } + + public void setContainsEntity(boolean containsEntity) { + this.containsEntity = containsEntity; + } } diff --git a/src/main/java/ru/ulstu/extractor/service/GitRepositoryService.java b/src/main/java/ru/ulstu/extractor/service/GitRepositoryService.java index 3f50e52..0cc4f15 100644 --- a/src/main/java/ru/ulstu/extractor/service/GitRepositoryService.java +++ b/src/main/java/ru/ulstu/extractor/service/GitRepositoryService.java @@ -12,10 +12,15 @@ import org.eclipse.jgit.api.ListBranchCommand; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.diff.DiffFormatter; import org.eclipse.jgit.internal.storage.file.FileRepository; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectLoader; +import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.treewalk.TreeWalk; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import ru.ulstu.extractor.heuristic.service.StructuralUnitService; import ru.ulstu.extractor.model.Author; import ru.ulstu.extractor.model.Branch; import ru.ulstu.extractor.model.Commit; @@ -28,6 +33,7 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.time.Instant; import java.util.ArrayList; @@ -44,6 +50,12 @@ public class GitRepositoryService { @Value("${extractor.custom-projects-dir}") private String customProjectsDir; + private final StructuralUnitService structuralUnitService; + + public GitRepositoryService(StructuralUnitService structuralUnitService) { + this.structuralUnitService = structuralUnitService; + } + public List getRemoteBranches(String url) throws GitAPIException, IOException { cloneOrUpdateRepo(url); Repository localRepo = new FileRepository(getProjectGitDirectory(url)); @@ -177,10 +189,10 @@ public class GitRepositoryService { } catch (IOException e) { throw new RuntimeException("Error occurred during diff computation. Message: " + e.getMessage()); } - return parseOutputDiff(output); + return parseOutputDiff(output, localRepo, laterCommit); } - private List parseOutputDiff(String output) { + private List parseOutputDiff(String output, Repository repository, RevCommit commit) { List changes = new ArrayList<>(); String[] strings = output.split("\n"); FileChange fileChange = new FileChange(); @@ -191,6 +203,9 @@ public class GitRepositoryService { if (maybeFileName.isPresent()) { fileChange = new FileChange(); fileChange.setFile(maybeFileName.get()); + fileChange.setContainsEntity( + structuralUnitService.containsEntity(getContent(repository, commit, maybeFileName.get())) + ); /// вытащить другие изменения из коммита changes.add(fileChange); } @@ -226,6 +241,22 @@ public class GitRepositoryService { return changes; } + private String getContent(Repository repository, RevCommit commit, String path) { + try (TreeWalk treeWalk = TreeWalk.forPath(repository, path, commit.getTree())) { + if (treeWalk != null) { + ObjectId blobId = treeWalk.getObjectId(0); + try (ObjectReader objectReader = repository.newObjectReader()) { + ObjectLoader objectLoader = objectReader.open(blobId); + byte[] bytes = objectLoader.getBytes(); + return new String(bytes, StandardCharsets.UTF_8); + } + } + } catch (Exception ex) { + ex.printStackTrace(); + } + return ""; + } + private Optional getFileName(String commitString) { String startString = "diff --git a/"; if (commitString.startsWith(startString)) {