Merge branch '20-detect-bl' into 'master'

Resolve "Определять классы, содержащие бизнес-логику"

Closes #20

See merge request romanov73/git-extractor!17
merge-requests/21/merge
Anton Romanov 3 years ago
commit 4fd8a510f3

@ -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.config; package ru.ulstu.extractor.config;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
@ -6,10 +11,12 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException; import org.springframework.web.servlet.NoHandlerFoundException;
import springfox.documentation.annotations.ApiIgnore;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ControllerAdvice @ControllerAdvice
@ApiIgnore
class GlobalDefaultExceptionHandler { class GlobalDefaultExceptionHandler {
public static final String DEFAULT_ERROR_VIEW = "error"; public static final String DEFAULT_ERROR_VIEW = "error";

@ -11,10 +11,12 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import ru.ulstu.extractor.repository.BranchRepository; import ru.ulstu.extractor.repository.BranchRepository;
import ru.ulstu.extractor.repository.RepositoryRepository; import ru.ulstu.extractor.repository.RepositoryRepository;
import springfox.documentation.annotations.ApiIgnore;
import static ru.ulstu.extractor.controller.Route.LIST_REPOSITORY_BRANCHES; import static ru.ulstu.extractor.controller.Route.LIST_REPOSITORY_BRANCHES;
@Controller @Controller
@ApiIgnore
public class BranchController { public class BranchController {
private final RepositoryRepository repositoryRepository; private final RepositoryRepository repositoryRepository;
private final BranchRepository branchRepository; private final BranchRepository branchRepository;

@ -15,6 +15,7 @@ import ru.ulstu.extractor.model.Commit;
import ru.ulstu.extractor.model.OffsetablePageRequest; import ru.ulstu.extractor.model.OffsetablePageRequest;
import ru.ulstu.extractor.model.mvc.FilterForm; import ru.ulstu.extractor.model.mvc.FilterForm;
import ru.ulstu.extractor.service.FilteringService; import ru.ulstu.extractor.service.FilteringService;
import springfox.documentation.annotations.ApiIgnore;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -24,6 +25,7 @@ import java.util.stream.IntStream;
import static ru.ulstu.extractor.controller.Route.FILTER_COMMITS; import static ru.ulstu.extractor.controller.Route.FILTER_COMMITS;
@Controller @Controller
@ApiIgnore
public class GitFilteringController { public class GitFilteringController {
private final static int DEFAULT_PAGE_SIZE = 20; private final static int DEFAULT_PAGE_SIZE = 20;
private final FilteringService filteringService; private final FilteringService filteringService;

@ -20,6 +20,7 @@ import ru.ulstu.extractor.model.mvc.FilterForm;
import ru.ulstu.extractor.model.mvc.RepoForm; import ru.ulstu.extractor.model.mvc.RepoForm;
import ru.ulstu.extractor.service.GitRepositoryService; import ru.ulstu.extractor.service.GitRepositoryService;
import ru.ulstu.extractor.service.IndexService; import ru.ulstu.extractor.service.IndexService;
import springfox.documentation.annotations.ApiIgnore;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -28,6 +29,7 @@ import static ru.ulstu.extractor.controller.Route.FILTER_COMMITS;
import static ru.ulstu.extractor.controller.Route.INDEXING_NEW_REPOSITORY; import static ru.ulstu.extractor.controller.Route.INDEXING_NEW_REPOSITORY;
@Controller @Controller
@ApiIgnore
public class GitIndexingController { public class GitIndexingController {
private final static Logger LOG = LoggerFactory.getLogger(GitIndexingController.class); private final static Logger LOG = LoggerFactory.getLogger(GitIndexingController.class);
private final GitRepositoryService gitRepositoryService; private final GitRepositoryService gitRepositoryService;

@ -9,10 +9,12 @@ import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import ru.ulstu.extractor.repository.RepositoryRepository; import ru.ulstu.extractor.repository.RepositoryRepository;
import springfox.documentation.annotations.ApiIgnore;
import static ru.ulstu.extractor.controller.Route.LIST_INDEXED_REPOSITORIES; import static ru.ulstu.extractor.controller.Route.LIST_INDEXED_REPOSITORIES;
@Controller @Controller
@ApiIgnore
public class RepositoryController { public class RepositoryController {
private final RepositoryRepository repositoryRepository; private final RepositoryRepository repositoryRepository;

@ -9,6 +9,7 @@ import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import ru.ulstu.extractor.repository.CommitRepository; import ru.ulstu.extractor.repository.CommitRepository;
import springfox.documentation.annotations.ApiIgnore;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -16,6 +17,7 @@ import java.util.stream.Collectors;
import static ru.ulstu.extractor.controller.Route.STATISTIC; import static ru.ulstu.extractor.controller.Route.STATISTIC;
@Controller @Controller
@ApiIgnore
public class StatisticController { public class StatisticController {
private final CommitRepository commitRepository; private final CommitRepository commitRepository;

@ -7,7 +7,8 @@ package ru.ulstu.extractor.heuristic.api;
import ru.ulstu.extractor.heuristic.component.BuildTool; import ru.ulstu.extractor.heuristic.component.BuildTool;
import ru.ulstu.extractor.heuristic.component.ProgrammingLanguage; import ru.ulstu.extractor.heuristic.component.ProgrammingLanguage;
import ru.ulstu.extractor.heuristic.model.StructuralUnit; import ru.ulstu.extractor.heuristic.model.BusinessLogicUnit;
import ru.ulstu.extractor.heuristic.model.EntityUnit;
import ru.ulstu.extractor.heuristic.service.DetectorService; import ru.ulstu.extractor.heuristic.service.DetectorService;
import ru.ulstu.extractor.heuristic.service.ProgrammingLanguageService; import ru.ulstu.extractor.heuristic.service.ProgrammingLanguageService;
import ru.ulstu.extractor.util.StringUtils; import ru.ulstu.extractor.util.StringUtils;
@ -24,11 +25,16 @@ import static ru.ulstu.extractor.heuristic.service.DetectorService.LangDetectScr
import static ru.ulstu.extractor.heuristic.service.DetectorService.LangDetectScrupulousness.LOW; import static ru.ulstu.extractor.heuristic.service.DetectorService.LangDetectScrupulousness.LOW;
public abstract class StructuralUnitIdentifier { public abstract class StructuralUnitIdentifier {
public List<StructuralUnit> getEntityClasses(String projectPath, List<File> projectFiles, List<File> rootProjectFiles) { public List<EntityUnit> getEntityClasses(String projectPath, List<File> projectFiles, List<File> rootProjectFiles) {
String subDirectory = getSourceDirectory(rootProjectFiles); String subDirectory = getSourceDirectory(rootProjectFiles);
return getEntityClasses(projectPath, subDirectory, projectFiles); return getEntityClasses(projectPath, subDirectory, projectFiles);
} }
public List<BusinessLogicUnit> getBusinessLogicClasses(String projectPath, List<File> projectFiles, List<File> rootProjectFiles) {
String subDirectory = getSourceDirectory(rootProjectFiles);
return getBusinessLogicClasses(projectPath, subDirectory, projectFiles);
}
public abstract boolean canAppliedToCode(String sourceCode); public abstract boolean canAppliedToCode(String sourceCode);
public abstract boolean canAppliedToFile(File projectFile); public abstract boolean canAppliedToFile(File projectFile);
@ -39,15 +45,17 @@ public abstract class StructuralUnitIdentifier {
public abstract boolean isEntityClass(String sourceCode); public abstract boolean isEntityClass(String sourceCode);
public abstract boolean isBusinessLogicClass(String sourceCode);
protected abstract boolean isBusinessLogicClass(File file); protected abstract boolean isBusinessLogicClass(File file);
public abstract List<StructuralUnit> getBusinessLogicClasses(); public abstract List<BusinessLogicUnit> getBusinessLogicClasses(String projectPath, String subDirectory, List<File> projectFiles);
public abstract boolean isMultiModuleProject(); public abstract boolean isMultiModuleProject();
public abstract Optional<BuildTool> getBuildTool(List<File> rootDirectoryFiles); public abstract Optional<BuildTool> getBuildTool(List<File> rootDirectoryFiles);
protected abstract List<StructuralUnit> getEntityClasses(String projectPath, String subDirectory, List<File> projectFiles); protected abstract List<EntityUnit> getEntityClasses(String projectPath, String subDirectory, List<File> projectFiles);
protected abstract String getSourceDirectory(List<File> rootProjectFiles); protected abstract String getSourceDirectory(List<File> rootProjectFiles);

@ -8,7 +8,8 @@ package ru.ulstu.extractor.heuristic.controller;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import ru.ulstu.extractor.heuristic.model.StructuralUnit; import ru.ulstu.extractor.heuristic.model.BusinessLogicUnit;
import ru.ulstu.extractor.heuristic.model.EntityUnit;
import ru.ulstu.extractor.heuristic.service.StructuralUnitService; import ru.ulstu.extractor.heuristic.service.StructuralUnitService;
import ru.ulstu.extractor.service.GitRepositoryService; import ru.ulstu.extractor.service.GitRepositoryService;
@ -29,8 +30,14 @@ public class StructuralUnitController {
} }
@GetMapping("get-entities") @GetMapping("get-entities")
public List<StructuralUnit> getEntities(String repositoryUrl) throws IOException { public List<EntityUnit> getEntities(String repositoryUrl) throws IOException {
File rootPath = gitRepositoryService.getProjectDirectoryFile(repositoryUrl); File rootPath = gitRepositoryService.getProjectDirectoryFile(repositoryUrl);
return structuralUnitService.getEntities(rootPath); return structuralUnitService.getEntities(rootPath);
} }
@GetMapping("get-business-logic")
public List<BusinessLogicUnit> getBusinessLogic(String repositoryUrl) throws IOException {
File rootPath = gitRepositoryService.getProjectDirectoryFile(repositoryUrl);
return structuralUnitService.getBusinessLogic(rootPath);
}
} }

@ -0,0 +1,15 @@
/*
* 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.heuristic.model;
import java.io.File;
public class BusinessLogicUnit extends StructuralUnit {
public BusinessLogicUnit(String projectPath, File file) {
super(projectPath, file);
}
}

@ -13,8 +13,8 @@ import ru.ulstu.extractor.heuristic.api.StructuralUnitIdentifier;
import ru.ulstu.extractor.heuristic.component.BuildTool; import ru.ulstu.extractor.heuristic.component.BuildTool;
import ru.ulstu.extractor.heuristic.component.JavaProgrammingLanguage; import ru.ulstu.extractor.heuristic.component.JavaProgrammingLanguage;
import ru.ulstu.extractor.heuristic.component.ProgrammingLanguage; import ru.ulstu.extractor.heuristic.component.ProgrammingLanguage;
import ru.ulstu.extractor.heuristic.model.BusinessLogicUnit;
import ru.ulstu.extractor.heuristic.model.EntityUnit; import ru.ulstu.extractor.heuristic.model.EntityUnit;
import ru.ulstu.extractor.heuristic.model.StructuralUnit;
import ru.ulstu.extractor.util.StringUtils; import ru.ulstu.extractor.util.StringUtils;
import java.io.File; import java.io.File;
@ -29,6 +29,7 @@ import static ru.ulstu.extractor.heuristic.service.DetectorService.LangDetectScr
@Service @Service
public class JavaIdentifier extends StructuralUnitIdentifier { public class JavaIdentifier extends StructuralUnitIdentifier {
private static final String ENTITY_ANNOTATION = "@Entity"; private static final String ENTITY_ANNOTATION = "@Entity";
private static final String SERVICE_ANNOTATION = "@Service";
private final DetectorService detectorService; private final DetectorService detectorService;
private final BuildToolService buildToolService; private final BuildToolService buildToolService;
private final ProgrammingLanguageService programmingLanguageService; private final ProgrammingLanguageService programmingLanguageService;
@ -56,7 +57,7 @@ public class JavaIdentifier extends StructuralUnitIdentifier {
} }
@Override @Override
public List<StructuralUnit> getEntityClasses(String projectPath, String subDirectory, List<File> projectFiles) { public List<EntityUnit> getEntityClasses(String projectPath, String subDirectory, List<File> projectFiles) {
return projectFiles.stream() return projectFiles.stream()
.filter(file -> StringUtils.fileInSubdirectory(file.getPath(), projectPath, subDirectory)) .filter(file -> StringUtils.fileInSubdirectory(file.getPath(), projectPath, subDirectory))
.filter(this::isEntityClass) .filter(this::isEntityClass)
@ -64,15 +65,14 @@ public class JavaIdentifier extends StructuralUnitIdentifier {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
protected Optional<ProgrammingLanguage> getMainProgrammingLanguage(String sourceCode) {
return sourceCodeContainsClass(sourceCode)
? Optional.of(getProgrammingLanguage())
: Optional.empty();
}
@Override @Override
public List<StructuralUnit> getBusinessLogicClasses() { public List<BusinessLogicUnit> getBusinessLogicClasses(String projectPath, String subDirectory, List<File> projectFiles) {
return null; return projectFiles.stream()
.filter(file -> StringUtils.fileInSubdirectory(file.getPath(), projectPath, subDirectory))
.filter(this::isBusinessLogicClass)
.map(file -> new BusinessLogicUnit(projectPath, file))
.collect(Collectors.toList());
} }
@Override @Override
@ -85,6 +85,12 @@ public class JavaIdentifier extends StructuralUnitIdentifier {
return buildToolService.getProjectBuildTool(rootDirectoryFiles); return buildToolService.getProjectBuildTool(rootDirectoryFiles);
} }
protected Optional<ProgrammingLanguage> getMainProgrammingLanguage(String sourceCode) {
return sourceCodeContainsClass(sourceCode)
? Optional.of(getProgrammingLanguage())
: Optional.empty();
}
@Override @Override
protected DetectorService getDetectorService() { protected DetectorService getDetectorService() {
return detectorService; return detectorService;
@ -120,6 +126,16 @@ public class JavaIdentifier extends StructuralUnitIdentifier {
return false; return false;
} }
@Override
public boolean isBusinessLogicClass(String sourceCode) {
try {
return classContainsAnnotation(sourceCode, SERVICE_ANNOTATION);
} catch (Exception ex) {
ex.printStackTrace();
}
return false;
}
private boolean classContainsAnnotation(File file, String annotationDeclaration) throws IOException { private boolean classContainsAnnotation(File file, String annotationDeclaration) throws IOException {
return classContainsAnnotation(new String(Files.readAllBytes(file.toPath())), annotationDeclaration); return classContainsAnnotation(new String(Files.readAllBytes(file.toPath())), annotationDeclaration);
} }
@ -152,6 +168,11 @@ public class JavaIdentifier extends StructuralUnitIdentifier {
@Override @Override
protected boolean isBusinessLogicClass(File file) { protected boolean isBusinessLogicClass(File file) {
try {
return file.getName().endsWith("java") && classContainsAnnotation(file, SERVICE_ANNOTATION);
} catch (Exception ex) {
ex.printStackTrace();
}
return false; return false;
} }
} }

@ -7,7 +7,8 @@ package ru.ulstu.extractor.heuristic.service;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.ulstu.extractor.heuristic.api.StructuralUnitIdentifier; import ru.ulstu.extractor.heuristic.api.StructuralUnitIdentifier;
import ru.ulstu.extractor.heuristic.model.StructuralUnit; import ru.ulstu.extractor.heuristic.model.BusinessLogicUnit;
import ru.ulstu.extractor.heuristic.model.EntityUnit;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -26,7 +27,7 @@ public class StructuralUnitService {
this.structuralUnitIdentifiers = structuralUnitIdentifiers; this.structuralUnitIdentifiers = structuralUnitIdentifiers;
} }
public List<StructuralUnit> getEntities(File rootPath) throws IOException { public List<EntityUnit> getEntities(File rootPath) throws IOException {
List<File> projectFiles = directoryService.getFilesRecursively(rootPath); List<File> projectFiles = directoryService.getFilesRecursively(rootPath);
List<File> rootProjectFiles = directoryService.getDirectoryFiles(rootPath.toPath()); List<File> rootProjectFiles = directoryService.getDirectoryFiles(rootPath.toPath());
return getStructuralUnitIdentifier( return getStructuralUnitIdentifier(
@ -38,6 +39,18 @@ public class StructuralUnitService {
.getEntityClasses(rootPath.getPath(), projectFiles, rootProjectFiles); .getEntityClasses(rootPath.getPath(), projectFiles, rootProjectFiles);
} }
public List<BusinessLogicUnit> getBusinessLogic(File rootPath) throws IOException {
List<File> projectFiles = directoryService.getFilesRecursively(rootPath);
List<File> rootProjectFiles = directoryService.getDirectoryFiles(rootPath.toPath());
return getStructuralUnitIdentifier(
structuralUnitIdentifier -> structuralUnitIdentifier.canAppliedToProject(
rootPath.getPath(),
projectFiles,
rootProjectFiles))
.orElseThrow(() -> new RuntimeException("Identifier not found"))
.getBusinessLogicClasses(rootPath.getPath(), projectFiles, rootProjectFiles);
}
public boolean containsEntity(File projectFile) { public boolean containsEntity(File projectFile) {
return getStructuralUnitIdentifier( return getStructuralUnitIdentifier(
structuralUnitIdentifier -> structuralUnitIdentifier.canAppliedToFile(projectFile)) structuralUnitIdentifier -> structuralUnitIdentifier.canAppliedToFile(projectFile))
@ -57,4 +70,11 @@ public class StructuralUnitService {
.filter(predicate) .filter(predicate)
.findAny(); .findAny();
} }
public boolean containsBusinessLogic(String sourceCode) {
return getStructuralUnitIdentifier(
structuralUnitIdentifier -> structuralUnitIdentifier.canAppliedToCode(sourceCode))
.map(identifier -> identifier.isBusinessLogicClass(sourceCode))
.orElse(false);
}
} }

@ -27,6 +27,8 @@ public class FileChange extends BaseEntity {
private Boolean containsEntity; private Boolean containsEntity;
private Boolean containsBusinessLogic;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "file_change_id", unique = true) @JoinColumn(name = "file_change_id", unique = true)
@Fetch(FetchMode.SUBSELECT) @Fetch(FetchMode.SUBSELECT)
@ -86,4 +88,20 @@ public class FileChange extends BaseEntity {
public void setContainsEntity(boolean containsEntity) { public void setContainsEntity(boolean containsEntity) {
this.containsEntity = containsEntity; this.containsEntity = containsEntity;
} }
public Boolean getContainsEntity() {
return containsEntity;
}
public void setContainsEntity(Boolean containsEntity) {
this.containsEntity = containsEntity;
}
public Boolean getContainsBusinessLogic() {
return containsBusinessLogic;
}
public void setContainsBusinessLogic(Boolean containsBusinessLogic) {
this.containsBusinessLogic = containsBusinessLogic;
}
} }

@ -206,6 +206,9 @@ public class GitRepositoryService {
fileChange.setContainsEntity( fileChange.setContainsEntity(
structuralUnitService.containsEntity(getContent(repository, commit, maybeFileName.get())) structuralUnitService.containsEntity(getContent(repository, commit, maybeFileName.get()))
); );
fileChange.setContainsBusinessLogic(
structuralUnitService.containsBusinessLogic(getContent(repository, commit, maybeFileName.get()))
);
/// вытащить другие изменения из коммита /// вытащить другие изменения из коммита
changes.add(fileChange); changes.add(fileChange);
} }

@ -12,4 +12,9 @@
<column name="contains_entity" type="boolean"/> <column name="contains_entity" type="boolean"/>
</addColumn> </addColumn>
</changeSet> </changeSet>
<changeSet author="orion" id="20210419-100000-1">
<addColumn tableName="file_change">
<column name="contains_business_logic" type="boolean"/>
</addColumn>
</changeSet>
</databaseChangeLog> </databaseChangeLog>
Loading…
Cancel
Save