Merge pull request 'Временные ряды' (#59) from influx into master

Reviewed-on: #59
pull/63/head
romanov73 2 years ago
commit 4c9ace2dd6

@ -1,8 +1,3 @@
/*
* Copyright (C) 2021 Anton Romanov - All Rights Reserved
* You may use, distribute and modify this code, please write to: romanov73@gmail.com.
*/
buildscript {
ext {
versionSpringBoot = '2.3.9.RELEASE'
@ -53,6 +48,9 @@ dependencies {
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-jetty'
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf'
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa'
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-webflux'
implementation group: 'org.json', name: 'json', version: '20220320'
implementation group: 'nz.net.ultraq.thymeleaf', name: 'thymeleaf-layout-dialect'
implementation group: 'com.fasterxml.jackson.module', name: 'jackson-module-afterburner'
implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-hibernate5'
@ -61,6 +59,7 @@ dependencies {
implementation group: 'commons-io', name: 'commons-io', version: '2.6'
implementation group: 'net.sourceforge.htmlunit', name: 'htmlunit', version: '2.35.0'
implementation group: 'com.github.javaparser', name: 'javaparser-core', version: '3.20.2'
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0'
implementation group: 'io.springfox', name: 'springfox-boot-starter', version: '3.0.0'

@ -2,8 +2,10 @@ package ru.ulstu.extractor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class GitExtractorApplication {
public static void main(String[] args) {
SpringApplication.run(GitExtractorApplication.class, args);

@ -3,14 +3,14 @@
* You may use, distribute and modify this code, please write to: romanov73@gmail.com.
*/
package ru.ulstu.extractor.controller;
package ru.ulstu.extractor.branch.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import ru.ulstu.extractor.repository.BranchRepository;
import ru.ulstu.extractor.repository.RepositoryRepository;
import ru.ulstu.extractor.branch.repository.BranchRepository;
import ru.ulstu.extractor.gitrepository.GitRepositoryRepository;
import springfox.documentation.annotations.ApiIgnore;
import static ru.ulstu.extractor.controller.Route.DELETE_BRANCH;
@ -19,11 +19,11 @@ import static ru.ulstu.extractor.controller.Route.LIST_REPOSITORY_BRANCHES;
@Controller
@ApiIgnore
public class BranchController {
private final RepositoryRepository repositoryRepository;
private final GitRepositoryRepository gitRepositoryRepository;
private final BranchRepository branchRepository;
public BranchController(RepositoryRepository repositoryRepository, BranchRepository branchRepository) {
this.repositoryRepository = repositoryRepository;
public BranchController(GitRepositoryRepository gitRepositoryRepository, BranchRepository branchRepository) {
this.gitRepositoryRepository = gitRepositoryRepository;
this.branchRepository = branchRepository;
}
@ -31,8 +31,8 @@ public class BranchController {
public String indexBranch(
Model model,
@RequestParam int repositoryId) {
model.addAttribute("branches", branchRepository.findByRepositoryId(repositoryId));
model.addAttribute("repository", repositoryRepository.findById(repositoryId).get());
model.addAttribute("branches", branchRepository.findByGitRepositoryId(repositoryId));
model.addAttribute("repository", gitRepositoryRepository.findById(repositoryId).get());
return LIST_REPOSITORY_BRANCHES;
}
@ -41,8 +41,8 @@ public class BranchController {
@RequestParam int repositoryId,
@RequestParam Integer id) {
branchRepository.deleteById(id);
model.addAttribute("branches", branchRepository.findByRepositoryId(repositoryId));
model.addAttribute("repository", repositoryRepository.findById(repositoryId).get());
model.addAttribute("branches", branchRepository.findByGitRepositoryId(repositoryId));
model.addAttribute("repository", gitRepositoryRepository.findById(repositoryId).get());
return LIST_REPOSITORY_BRANCHES;
}
}

@ -3,10 +3,13 @@
* You may use, distribute and modify this code, please write to: romanov73@gmail.com.
*/
package ru.ulstu.extractor.model;
package ru.ulstu.extractor.branch.model;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import ru.ulstu.extractor.gitrepository.model.GitRepository;
import ru.ulstu.extractor.model.BaseEntity;
import ru.ulstu.extractor.model.Commit;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
@ -22,7 +25,7 @@ public class Branch extends BaseEntity {
private String name;
@ManyToOne
private Repository repository;
private GitRepository gitRepository;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "branch_id")
@ -36,8 +39,8 @@ public class Branch extends BaseEntity {
this.name = name;
}
public Branch(Repository repository, String branchName) {
this.repository = repository;
public Branch(GitRepository gitRepository, String branchName) {
this.gitRepository = gitRepository;
this.name = branchName;
}
@ -49,12 +52,12 @@ public class Branch extends BaseEntity {
this.name = name;
}
public Repository getRepository() {
return repository;
public GitRepository getGitRepository() {
return gitRepository;
}
public void setRepository(Repository repository) {
this.repository = repository;
public void setGitRepository(GitRepository gitRepository) {
this.gitRepository = gitRepository;
}
public List<Commit> getCommits() {

@ -0,0 +1,21 @@
package ru.ulstu.extractor.branch.repository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import ru.ulstu.extractor.branch.model.Branch;
import ru.ulstu.extractor.gitrepository.model.GitRepository;
import java.util.List;
public interface BranchRepository extends JpaRepository<Branch, Integer> {
Branch findByGitRepositoryAndName(GitRepository gitRepository, String name);
@Query("select count(c) from Commit c LEFT JOIN c.branch b LEFT JOIN GitRepository r where r.id = ?1 AND b.name = ?2")
int getCommitsCount(Integer repositoryId, String name);
List<Branch> findByGitRepositoryId(Integer repositoryId);
Page<Branch> findByGitRepository(GitRepository gitRepository, Pageable pageable);
}

@ -3,16 +3,18 @@
* You may use, distribute and modify this code, please write to: romanov73@gmail.com.
*/
package ru.ulstu.extractor.service;
package ru.ulstu.extractor.branch.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.ulstu.extractor.branch.model.Branch;
import ru.ulstu.extractor.branch.repository.BranchRepository;
import ru.ulstu.extractor.commit.service.CommitService;
import ru.ulstu.extractor.gitrepository.model.GitRepository;
import ru.ulstu.extractor.model.BaseEntity;
import ru.ulstu.extractor.model.Branch;
import ru.ulstu.extractor.model.Commit;
import ru.ulstu.extractor.model.Repository;
import ru.ulstu.extractor.repository.BranchRepository;
import java.util.List;
import java.util.stream.Collectors;
@ -29,6 +31,7 @@ public class BranchService {
this.commitService = commitService;
}
@Transactional
public Branch save(Branch branch, List<Commit> commits) {
LOG.debug("Start save {} branch with {} commits ", branch.getName(), commits.size());
List<Integer> commitsToRemoveIds = branch.getCommits().stream().map(BaseEntity::getId).collect(Collectors.toList());
@ -48,8 +51,8 @@ public class BranchService {
return branch;
}
public Branch findByRepositoryAndName(Repository repository, String branchName) {
return branchRepository.findByRepositoryAndName(repository, branchName);
public Branch findByRepositoryAndName(GitRepository gitRepository, String branchName) {
return branchRepository.findByGitRepositoryAndName(gitRepository, branchName);
}
public List<Branch> findAll() {

@ -7,6 +7,7 @@ package ru.ulstu.extractor.model;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import ru.ulstu.extractor.branch.model.Branch;
import javax.persistence.CascadeType;
import javax.persistence.Entity;

@ -1,4 +1,4 @@
package ru.ulstu.extractor.model;
package ru.ulstu.extractor.commit.model;
public class CommitAuthorStatistic {
private String author;

@ -1,4 +1,4 @@
package ru.ulstu.extractor.model;
package ru.ulstu.extractor.commit.model;
public class CommitEntityStatistic {
private Boolean entity;

@ -1,4 +1,4 @@
package ru.ulstu.extractor.model;
package ru.ulstu.extractor.commit.model;
public class CommitTimeStatistic {
private final static String DATE_TEMPLATE = "%s.%s";

@ -1,4 +1,4 @@
package ru.ulstu.extractor.model;
package ru.ulstu.extractor.commit.model;
public class CommitUrlStatistic {
private String url;

@ -0,0 +1,45 @@
/*
* 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.commit.repository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import ru.ulstu.extractor.commit.model.CommitAuthorStatistic;
import ru.ulstu.extractor.commit.model.CommitEntityStatistic;
import ru.ulstu.extractor.commit.model.CommitTimeStatistic;
import ru.ulstu.extractor.commit.model.CommitUrlStatistic;
import ru.ulstu.extractor.gitrepository.model.GitRepository;
import ru.ulstu.extractor.model.Commit;
import java.util.List;
public interface CommitRepository extends JpaRepository<Commit, Integer> {
@Query("SELECT DISTINCT c FROM Commit c LEFT JOIN c.branch b LEFT JOIN c.fileChanges f LEFT JOIN c.author a LEFT JOIN b.gitRepository r WHERE r = :repository AND b.name = :branchName AND (:author IS NULL OR :author = '' OR a.name = :author) AND (:filter IS NULL OR :filter = '' OR lower(c.message) LIKE lower(concat('%', :filter,'%'))) AND (:entity IS NULL OR f.containsEntity = :entity)")
Page<Commit> findByRepositoryAndBranch(Pageable pageable, @Param("repository") GitRepository gitRepository, @Param("branchName") String branchName, @Param("author") String author, @Param("filter") String filter, @Param("entity") Boolean entity);
@Query("SELECT new ru.ulstu.extractor.commit.model.CommitAuthorStatistic(c.author.name, COUNT(DISTINCT c.hash)) FROM Commit c LEFT JOIN c.branch LEFT JOIN c.author a WHERE (:branchId IS NULL OR c.branch.id = :branchId) AND (:author IS NULL OR :author = '' OR a.name = :author) GROUP by c.author.name")
List<CommitAuthorStatistic> getCommitAuthorStatistic(@Param("branchId") Integer branchId, @Param("author") String author);
@Query("SELECT new ru.ulstu.extractor.commit.model.CommitUrlStatistic(c.branch.gitRepository.url, COUNT(DISTINCT c.hash)) FROM Commit c GROUP by c.branch.gitRepository.url")
List<CommitUrlStatistic> getCommitUrlStatistic();
@Query("SELECT new ru.ulstu.extractor.commit.model.CommitTimeStatistic(extract(month FROM c.date) as month, extract(year FROM c.date) as year, COUNT(DISTINCT c.hash)) FROM Commit c LEFT JOIN c.branch LEFT JOIN c.author a WHERE (:branchId IS NULL OR c.branch.id = :branchId) AND (:author IS NULL OR :author = '' OR a.name = :author) GROUP by extract(month from c.date), extract(year from c.date) ORDER by extract(year from c.date), extract(month from c.date)")
List<CommitTimeStatistic> getCommitTimeStatistic(@Param("branchId") Integer branchId, @Param("author") String author);
@Query("SELECT new ru.ulstu.extractor.commit.model.CommitEntityStatistic(f.containsEntity, COUNT(DISTINCT c.hash)) FROM Commit c LEFT JOIN c.branch LEFT JOIN c.author a LEFT JOIN c.fileChanges f WHERE (:branchId IS NULL OR c.branch.id = :branchId) AND (:author IS NULL OR :author = '' OR a.name = :author) GROUP by f.containsEntity")
List<CommitEntityStatistic> getCommitEntityStatistic(@Param("branchId") Integer branchId, @Param("author") String author);
@Query("SELECT new ru.ulstu.extractor.commit.model.CommitTimeStatistic(EXTRACT(MONTH FROM c.date), EXTRACT(YEAR FROM c.date), COUNT(DISTINCT c.hash)) FROM Commit c LEFT JOIN c.branch LEFT JOIN c.author a LEFT JOIN c.fileChanges f WHERE f.containsEntity = true AND (:branchId IS NULL OR c.branch.id = :branchId) AND (:author IS NULL OR :author = '' OR a.name = :author) GROUP by extract(month from c.date), extract(year from c.date) ORDER by extract(year from c.date), extract(month from c.date)")
List<CommitTimeStatistic> getCommitTimeEntityStatistic(@Param("branchId") Integer branchId, @Param("author") String author);
void deleteByBranchIsNull();
@Query("SELECT b.commits FROM Branch b WHERE b.name = ?2 and b.gitRepository.id = ?1")
List<Commit> findByRepositoryIdAndBranchName(Integer repositoryId, String name);
}

@ -3,12 +3,13 @@
* You may use, distribute and modify this code, please write to: romanov73@gmail.com.
*/
package ru.ulstu.extractor.service;
package ru.ulstu.extractor.commit.service;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import ru.ulstu.extractor.commit.repository.CommitRepository;
import ru.ulstu.extractor.model.Commit;
import ru.ulstu.extractor.repository.CommitRepository;
import ru.ulstu.extractor.service.AuthorService;
import java.util.List;
import java.util.stream.Collectors;
@ -49,6 +50,11 @@ public class CommitService {
updateQuery = String.format(updateQuery, String.join(",", commitIds));
jdbcTemplate.update(updateQuery, branchId);
}
public List<Commit> findByRepositoryIdAndName(Integer repositoryId, String branchName) {
return commitRepository.findByRepositoryIdAndBranchName(repositoryId, branchName);
}
}

@ -0,0 +1,13 @@
package ru.ulstu.extractor.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
@Configuration
public class WebClientConfiguration {
@Bean
public WebClient webClient(WebClient.Builder webClientBuilder) {
return webClientBuilder.build();
}
}

@ -15,10 +15,10 @@ import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import ru.ulstu.extractor.model.Branch;
import ru.ulstu.extractor.branch.model.Branch;
import ru.ulstu.extractor.gitrepository.GitRepositoryService;
import ru.ulstu.extractor.model.mvc.FilterForm;
import ru.ulstu.extractor.model.mvc.RepoForm;
import ru.ulstu.extractor.service.GitRepositoryService;
import ru.ulstu.extractor.service.IndexService;
import springfox.documentation.annotations.ApiIgnore;

@ -12,8 +12,8 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import ru.ulstu.extractor.gitrepository.GitRepositoryService;
import ru.ulstu.extractor.model.Commit;
import ru.ulstu.extractor.service.GitRepositoryService;
import ru.ulstu.extractor.service.IndexService;
import ru.ulstu.extractor.util.HttpUtils;

@ -9,7 +9,7 @@ import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import ru.ulstu.extractor.repository.RepositoryRepository;
import ru.ulstu.extractor.gitrepository.GitRepositoryRepository;
import springfox.documentation.annotations.ApiIgnore;
import static ru.ulstu.extractor.controller.Route.DELETE_INDEXED_REPOSITORY;
@ -18,23 +18,23 @@ import static ru.ulstu.extractor.controller.Route.LIST_INDEXED_REPOSITORIES;
@Controller
@ApiIgnore
public class RepositoryController {
private final RepositoryRepository repositoryRepository;
private final GitRepositoryRepository gitRepositoryRepository;
public RepositoryController(RepositoryRepository repositoryRepository) {
this.repositoryRepository = repositoryRepository;
public RepositoryController(GitRepositoryRepository gitRepositoryRepository) {
this.gitRepositoryRepository = gitRepositoryRepository;
}
@GetMapping(LIST_INDEXED_REPOSITORIES)
public String indexNewRepo(Model model) {
model.addAttribute("repositories", repositoryRepository.findAll());
model.addAttribute("repositories", gitRepositoryRepository.findAll());
return LIST_INDEXED_REPOSITORIES;
}
@GetMapping(DELETE_INDEXED_REPOSITORY)
public String deleteRepo(Model model,
@RequestParam Integer id) {
repositoryRepository.deleteById(id);
model.addAttribute("repositories", repositoryRepository.findAll());
gitRepositoryRepository.deleteById(id);
model.addAttribute("repositories", gitRepositoryRepository.findAll());
return "redirect:/" + LIST_INDEXED_REPOSITORIES;
}
}

@ -9,9 +9,9 @@ import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import ru.ulstu.extractor.branch.service.BranchService;
import ru.ulstu.extractor.commit.repository.CommitRepository;
import ru.ulstu.extractor.model.mvc.FilterForm;
import ru.ulstu.extractor.repository.CommitRepository;
import ru.ulstu.extractor.service.BranchService;
import ru.ulstu.extractor.service.FilteringService;
import springfox.documentation.annotations.ApiIgnore;

@ -0,0 +1,8 @@
package ru.ulstu.extractor.gitrepository;
import org.springframework.data.jpa.repository.JpaRepository;
import ru.ulstu.extractor.gitrepository.model.GitRepository;
public interface GitRepositoryRepository extends JpaRepository<GitRepository, Integer> {
GitRepository findByUrl(String url);
}

@ -1,9 +1,4 @@
/*
* 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.service;
package ru.ulstu.extractor.gitrepository;
import org.apache.commons.io.FileUtils;
import org.eclipse.jgit.api.CreateBranchCommand;
@ -15,19 +10,21 @@ 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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import ru.ulstu.extractor.branch.model.Branch;
import ru.ulstu.extractor.gitrepository.model.GitRepository;
import ru.ulstu.extractor.heuristic.model.BusinessLogicUnit;
import ru.ulstu.extractor.heuristic.model.EntityUnit;
import ru.ulstu.extractor.heuristic.model.ResourceUnit;
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;
import ru.ulstu.extractor.model.FileChange;
import ru.ulstu.extractor.model.LineChange;
@ -61,18 +58,20 @@ public class GitRepositoryService {
private String customProjectsDir;
private final ExecutorService executorService = Executors.newFixedThreadPool(4);
private final ExecutorService executorServiceCommits = Executors.newFixedThreadPool(4);
private final StructuralUnitService structuralUnitService;
private final GitRepositoryRepository gitRepositoryRepository;
public GitRepositoryService(StructuralUnitService structuralUnitService) {
public GitRepositoryService(StructuralUnitService structuralUnitService,
GitRepositoryRepository gitRepositoryRepository) {
this.structuralUnitService = structuralUnitService;
this.gitRepositoryRepository = gitRepositoryRepository;
}
public List<Branch> getRemoteBranches(String url) throws GitAPIException, IOException {
LOG.debug("Get remote branches of {}. Clone", url);
cloneOrUpdateRepo(url);
LOG.debug("Get remote branches of {}. Get branches", url);
Repository localRepo = new FileRepository(getProjectGitDirectory(url));
org.eclipse.jgit.lib.Repository localRepo = new FileRepository(getProjectGitDirectory(url));
Git git = new Git(localRepo);
List<Branch> branches = git.branchList().setListMode(ListBranchCommand.ListMode.REMOTE)
.call()
@ -88,7 +87,7 @@ public class GitRepositoryService {
LOG.debug("Get local branches of {}. Clone", url);
cloneOrUpdateRepo(url);
LOG.debug("Get local branches of {}. Get branches", url);
Repository localRepo = new FileRepository(getProjectGitDirectory(url));
org.eclipse.jgit.lib.Repository localRepo = new FileRepository(getProjectGitDirectory(url));
Git git = new Git(localRepo);
List<Branch> branches = git.branchList()
.call()
@ -105,7 +104,7 @@ public class GitRepositoryService {
if (needUpdate) {
cloneOrUpdateRepo(repositoryUrl, branchName);
}
Repository localRepo = new FileRepository(getProjectGitDirectory(repositoryUrl));
org.eclipse.jgit.lib.Repository localRepo = new FileRepository(getProjectGitDirectory(repositoryUrl));
Git git = new Git(localRepo);
List<RevCommit> commits = new ArrayList<>();
@ -144,7 +143,7 @@ public class GitRepositoryService {
return list;
}
private void checkoutBranch(String repositoryUrl, Git git, Repository localRepo, String branchName) throws GitAPIException, IOException {
private void checkoutBranch(String repositoryUrl, Git git, org.eclipse.jgit.lib.Repository localRepo, String branchName) throws GitAPIException, IOException {
LOG.debug("Checkout branch {} {}", repositoryUrl, branchName);
git.pull().call();
if (!localRepo.getBranch().equals(branchName)) {
@ -192,7 +191,8 @@ public class GitRepositoryService {
private void cloneOrUpdateRepo(String repositoryUrl, String branchName) throws GitAPIException, IOException {
Git git;
Repository localRepo;
org.eclipse.jgit.lib.Repository localRepo;
validateOrClearRepositoryDirectory(getProjectDirectoryFile(repositoryUrl));
if (projectDirExists(getProjectDirectoryFile(repositoryUrl))) {
localRepo = new FileRepository(getProjectGitDirectory(repositoryUrl));
git = new Git(localRepo);
@ -211,6 +211,26 @@ public class GitRepositoryService {
git.close();
}
private void validateOrClearRepositoryDirectory(File projectDirectory) {
if (projectDirectory.exists()) {
try {
Git.open(projectDirectory).status().call();
} catch (Exception e) {
deleteDirectory(projectDirectory);
}
}
}
private boolean deleteDirectory(File directoryToBeDeleted) {
File[] allContents = directoryToBeDeleted.listFiles();
if (allContents != null) {
for (File file : allContents) {
deleteDirectory(file);
}
}
return directoryToBeDeleted.delete();
}
private void cloneOrUpdateRepo(String url) throws GitAPIException, IOException {
cloneOrUpdateRepo(url, null);
}
@ -240,7 +260,7 @@ public class GitRepositoryService {
return file.exists();
}
private List<FileChange> findDiffBetweenTwoRevisions(RevCommit laterCommit, RevCommit earlierCommit, Repository localRepo) {
private List<FileChange> findDiffBetweenTwoRevisions(RevCommit laterCommit, RevCommit earlierCommit, org.eclipse.jgit.lib.Repository localRepo) {
if (laterCommit == null || earlierCommit == null) {
return null;
}
@ -256,7 +276,7 @@ public class GitRepositoryService {
return parseOutputDiff(output, localRepo, laterCommit);
}
private List<FileChange> parseOutputDiff(String output, Repository repository, RevCommit commit) {
private List<FileChange> parseOutputDiff(String output, org.eclipse.jgit.lib.Repository repository, RevCommit commit) {
List<FileChange> changes = new ArrayList<>();
String[] strings = output.split("\n");
FileChange fileChange = new FileChange();
@ -322,7 +342,7 @@ public class GitRepositoryService {
return changes;
}
private String getContent(Repository repository, RevCommit commit, String path) {
private String getContent(org.eclipse.jgit.lib.Repository repository, RevCommit commit, String path) {
try (TreeWalk treeWalk = TreeWalk.forPath(repository, path, commit.getTree())) {
if (treeWalk != null) {
ObjectId blobId = treeWalk.getObjectId(0);
@ -346,4 +366,8 @@ public class GitRepositoryService {
}
return Optional.empty();
}
public Page<GitRepository> findAll(Pageable pageable) {
return gitRepositoryRepository.findAll(pageable);
}
}

@ -1,15 +1,17 @@
package ru.ulstu.extractor.model;
package ru.ulstu.extractor.gitrepository.model;
import ru.ulstu.extractor.model.BaseEntity;
import javax.persistence.Entity;
@Entity
public class Repository extends BaseEntity {
public class GitRepository extends BaseEntity {
private String url;
public Repository() {
public GitRepository() {
}
public Repository(String repositoryUrl) {
public GitRepository(String repositoryUrl) {
url = repositoryUrl;
}

@ -11,10 +11,10 @@ import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import ru.ulstu.extractor.gitrepository.GitRepositoryService;
import ru.ulstu.extractor.heuristic.model.BusinessLogicUnit;
import ru.ulstu.extractor.heuristic.model.EntityUnit;
import ru.ulstu.extractor.heuristic.model.ResourceUnit;
import ru.ulstu.extractor.service.GitRepositoryService;
import ru.ulstu.extractor.util.HttpUtils;
import javax.servlet.http.HttpServletRequest;

@ -0,0 +1,36 @@
package ru.ulstu.extractor.http;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import java.util.Optional;
@Service
public class HttpService {
private final Logger log = LoggerFactory.getLogger(HttpService.class);
private final WebClient client;
public HttpService(WebClient client) {
this.client = client;
}
public JSONObject post(String url, JSONObject postData) {
log.debug("Service call: {}", url);
JSONObject response = new JSONObject(Optional.ofNullable(client
.post()
.uri(url)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(postData.toString()))
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(String.class)
.block()).orElse("{response:\"empty\"}"));
log.debug("Service response: {}", response);
return response;
}
}

@ -0,0 +1,35 @@
package ru.ulstu.extractor.http;
import ru.ulstu.extractor.model.TimeSeries;
import java.util.List;
import java.util.stream.Collectors;
public class JsonTimeSeries {
private String name;
private List<JsonTimeSeriesValue> values;
public JsonTimeSeries(TimeSeries timeSeries) {
this.name = timeSeries.getName();
this.values = timeSeries.getValues()
.stream()
.map(JsonTimeSeriesValue::new)
.collect(Collectors.toList());
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<JsonTimeSeriesValue> getValues() {
return values;
}
public void setValues(List<JsonTimeSeriesValue> values) {
this.values = values;
}
}

@ -0,0 +1,35 @@
package ru.ulstu.extractor.http;
import ru.ulstu.extractor.model.TimeSeriesValue;
import java.time.LocalDateTime;
import java.time.ZoneId;
public class JsonTimeSeriesValue {
private LocalDateTime date;
private Double value;
public JsonTimeSeriesValue(TimeSeriesValue timeSeriesValue) {
this.value = timeSeriesValue.getValue();
this.date = timeSeriesValue.getDate()
.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime();
}
public LocalDateTime getDate() {
return date;
}
public void setDate(LocalDateTime date) {
this.date = date;
}
public Double getValue() {
return value;
}
public void setValue(Double value) {
this.value = value;
}
}

@ -0,0 +1,50 @@
package ru.ulstu.extractor.model;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import java.util.ArrayList;
import java.util.List;
@Entity
public class TimeSeries extends BaseEntity {
private String name;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "time_series_id")
@Fetch(FetchMode.SUBSELECT)
private List<TimeSeriesValue> values = new ArrayList<>();
public TimeSeries() {
}
public TimeSeries(String name) {
this.name = name;
}
public TimeSeries(String name, List<TimeSeriesValue> values) {
this.name = name;
this.values = values;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<TimeSeriesValue> getValues() {
return values;
}
public void setValues(List<TimeSeriesValue> values) {
this.values = values;
}
}

@ -0,0 +1,39 @@
package ru.ulstu.extractor.model;
import javax.persistence.Entity;
import java.util.Date;
@Entity
public class TimeSeriesValue extends BaseEntity {
private Date date;
private Double value;
public TimeSeriesValue() {
}
public TimeSeriesValue(Date date, Double value) {
this.date = date;
this.value = value;
}
public TimeSeriesValue(TimeSeries timeSeries, Date date, Double value) {
this.date = date;
this.value = value;
}
public Date getDate() {
return date;
}
public Double getValue() {
return value;
}
public void setDate(Date date) {
this.date = date;
}
public void setValue(Double value) {
this.value = value;
}
}

@ -8,14 +8,14 @@ package ru.ulstu.extractor.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import ru.ulstu.extractor.gitrepository.model.GitRepository;
import ru.ulstu.extractor.model.Author;
import ru.ulstu.extractor.model.Repository;
import java.util.List;
public interface AuthorRepository extends JpaRepository<Author, Integer> {
@Query("SELECT DISTINCT a.name FROM Commit c, Repository r, Branch b, Author a WHERE c.author = a AND c.branch = b AND r = b.repository AND (:repository IS NULL OR r = :repository) AND (:branchName IS NULL OR :branchName = '' OR b.name = :branchName) AND a.name IS NOT NULL AND a.name <> '' ORDER BY a.name")
List<String> findByRepositoryAndBranch(@Param("repository") Repository repository, @Param("branchName") String branchName);
@Query("SELECT DISTINCT a.name FROM Commit c, GitRepository r, Branch b, Author a WHERE c.author = a AND c.branch = b AND r = b.gitRepository AND (:repository IS NULL OR r = :repository) AND (:branchName IS NULL OR :branchName = '' OR b.name = :branchName) AND a.name IS NOT NULL AND a.name <> '' ORDER BY a.name")
List<String> findByRepositoryAndBranch(@Param("repository") GitRepository gitRepository, @Param("branchName") String branchName);
List<Author> findByName(String name);

@ -1,13 +0,0 @@
package ru.ulstu.extractor.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import ru.ulstu.extractor.model.Branch;
import ru.ulstu.extractor.model.Repository;
import java.util.List;
public interface BranchRepository extends JpaRepository<Branch, Integer> {
Branch findByRepositoryAndName(Repository repository, String name);
List<Branch> findByRepositoryId(Integer repositoryId);
}

@ -1,42 +0,0 @@
/*
* 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.repository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import ru.ulstu.extractor.model.Commit;
import ru.ulstu.extractor.model.CommitAuthorStatistic;
import ru.ulstu.extractor.model.CommitEntityStatistic;
import ru.ulstu.extractor.model.CommitTimeStatistic;
import ru.ulstu.extractor.model.CommitUrlStatistic;
import ru.ulstu.extractor.model.Repository;
import java.util.List;
public interface CommitRepository extends JpaRepository<Commit, Integer> {
@Query("SELECT DISTINCT c FROM Commit c LEFT JOIN c.branch b LEFT JOIN c.fileChanges f LEFT JOIN c.author a LEFT JOIN b.repository r WHERE r = :repository AND b.name = :branchName AND (:author IS NULL OR :author = '' OR a.name = :author) AND (:filter IS NULL OR :filter = '' OR lower(c.message) LIKE lower(concat('%', :filter,'%'))) AND (:entity IS NULL OR f.containsEntity = :entity)")
Page<Commit> findByRepositoryAndBranch(Pageable pageable, @Param("repository") Repository repository, @Param("branchName") String branchName, @Param("author") String author, @Param("filter") String filter, @Param("entity") Boolean entity);
@Query("SELECT new ru.ulstu.extractor.model.CommitAuthorStatistic(c.author.name, COUNT(DISTINCT c.hash)) FROM Commit c LEFT JOIN c.branch LEFT JOIN c.author a WHERE (:branchId IS NULL OR c.branch.id = :branchId) AND (:author IS NULL OR :author = '' OR a.name = :author) GROUP by c.author.name")
List<CommitAuthorStatistic> getCommitAuthorStatistic(@Param("branchId") Integer branchId, @Param("author") String author);
@Query("SELECT new ru.ulstu.extractor.model.CommitUrlStatistic(c.branch.repository.url, COUNT(DISTINCT c.hash)) FROM Commit c GROUP by c.branch.repository.url")
List<CommitUrlStatistic> getCommitUrlStatistic();
@Query("SELECT new ru.ulstu.extractor.model.CommitTimeStatistic(extract(month FROM c.date) as month, extract(year FROM c.date) as year, COUNT(DISTINCT c.hash)) FROM Commit c LEFT JOIN c.branch LEFT JOIN c.author a WHERE (:branchId IS NULL OR c.branch.id = :branchId) AND (:author IS NULL OR :author = '' OR a.name = :author) GROUP by extract(month from c.date), extract(year from c.date) ORDER by extract(year from c.date), extract(month from c.date)")
List<CommitTimeStatistic> getCommitTimeStatistic(@Param("branchId") Integer branchId, @Param("author") String author);
@Query("SELECT new ru.ulstu.extractor.model.CommitEntityStatistic(f.containsEntity, COUNT(DISTINCT c.hash)) FROM Commit c LEFT JOIN c.branch LEFT JOIN c.author a LEFT JOIN c.fileChanges f WHERE (:branchId IS NULL OR c.branch.id = :branchId) AND (:author IS NULL OR :author = '' OR a.name = :author) GROUP by f.containsEntity")
List<CommitEntityStatistic> getCommitEntityStatistic(@Param("branchId") Integer branchId, @Param("author") String author);
@Query("SELECT new ru.ulstu.extractor.model.CommitTimeStatistic(EXTRACT(MONTH FROM c.date), EXTRACT(YEAR FROM c.date), COUNT(DISTINCT c.hash)) FROM Commit c LEFT JOIN c.branch LEFT JOIN c.author a LEFT JOIN c.fileChanges f WHERE f.containsEntity = true AND (:branchId IS NULL OR c.branch.id = :branchId) AND (:author IS NULL OR :author = '' OR a.name = :author) GROUP by extract(month from c.date), extract(year from c.date) ORDER by extract(year from c.date), extract(month from c.date)")
List<CommitTimeStatistic> getCommitTimeEntityStatistic(@Param("branchId") Integer branchId, @Param("author") String author);
void deleteByBranchIsNull();
}

@ -1,8 +0,0 @@
package ru.ulstu.extractor.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import ru.ulstu.extractor.model.Repository;
public interface RepositoryRepository extends JpaRepository<Repository, Integer> {
Repository findByUrl(String url);
}

@ -0,0 +1,10 @@
package ru.ulstu.extractor.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import ru.ulstu.extractor.model.TimeSeries;
import java.util.Optional;
public interface TimeSeriesRepository extends JpaRepository<TimeSeries, Integer> {
Optional<TimeSeries> findByName(String name);
}

@ -0,0 +1,14 @@
package ru.ulstu.extractor.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import ru.ulstu.extractor.model.TimeSeriesValue;
import java.util.List;
public interface TimeSeriesValueRepository extends JpaRepository<TimeSeriesValue, Integer> {
//TimeSeriesValue findByTimeSeriesAndName(TimeSeries timeSeries, String name);
//List<TimeSeriesValue> findTimeSeriesValueById(Integer repositoryId);
void deleteAllByIdIn(List<Integer> ids);
}

@ -9,10 +9,10 @@ import com.sun.istack.NotNull;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import ru.ulstu.extractor.commit.repository.CommitRepository;
import ru.ulstu.extractor.gitrepository.GitRepositoryRepository;
import ru.ulstu.extractor.model.Commit;
import ru.ulstu.extractor.repository.AuthorRepository;
import ru.ulstu.extractor.repository.CommitRepository;
import ru.ulstu.extractor.repository.RepositoryRepository;
import java.util.List;
import java.util.Map;
@ -21,20 +21,20 @@ import java.util.Map;
public class FilteringService {
private final AuthorRepository authorRepository;
private final CommitRepository commitRepository;
private final RepositoryRepository repositoryRepository;
private final GitRepositoryRepository gitRepositoryRepository;
public FilteringService(AuthorRepository authorRepository,
CommitRepository commitRepository,
RepositoryRepository repositoryRepository) {
GitRepositoryRepository gitRepositoryRepository) {
this.authorRepository = authorRepository;
this.commitRepository = commitRepository;
this.repositoryRepository = repositoryRepository;
this.gitRepositoryRepository = gitRepositoryRepository;
}
public List<String> getRepositoryAuthors(@NotNull String repositoryUrl,
@NotNull String branchName) {
return authorRepository.findByRepositoryAndBranch(
repositoryRepository.findByUrl(repositoryUrl),
gitRepositoryRepository.findByUrl(repositoryUrl),
branchName
);
}
@ -51,7 +51,7 @@ public class FilteringService {
Pageable pageable) {
return commitRepository.findByRepositoryAndBranch(
pageable,
repositoryRepository.findByUrl(repositoryUrl),
gitRepositoryRepository.findByUrl(repositoryUrl),
branchName,
author,
filter,

@ -10,10 +10,13 @@ import org.eclipse.jgit.api.errors.GitAPIException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import ru.ulstu.extractor.model.Branch;
import ru.ulstu.extractor.branch.model.Branch;
import ru.ulstu.extractor.branch.service.BranchService;
import ru.ulstu.extractor.gitrepository.GitRepositoryRepository;
import ru.ulstu.extractor.gitrepository.GitRepositoryService;
import ru.ulstu.extractor.gitrepository.model.GitRepository;
import ru.ulstu.extractor.model.Commit;
import ru.ulstu.extractor.model.Repository;
import ru.ulstu.extractor.repository.RepositoryRepository;
import ru.ulstu.extractor.ts.AbstractTimeSeriesCreator;
import java.io.IOException;
import java.util.Collections;
@ -24,25 +27,28 @@ public class IndexService {
private final static Logger LOG = LoggerFactory.getLogger(IndexService.class);
private final static int COMMITS_PAGE_SIZE = 10;
private final GitRepositoryService gitRepositoryService;
private final RepositoryRepository repositoryRepository;
private final GitRepositoryRepository gitRepositoryRepository;
private final BranchService branchService;
private final List<AbstractTimeSeriesCreator> timeSeriesCreators;
public IndexService(GitRepositoryService gitRepositoryService,
RepositoryRepository repositoryRepository,
BranchService branchService) {
GitRepositoryRepository gitRepositoryRepository,
BranchService branchService,
List<AbstractTimeSeriesCreator> timeSeriesCreators) {
this.gitRepositoryService = gitRepositoryService;
this.repositoryRepository = repositoryRepository;
this.gitRepositoryRepository = gitRepositoryRepository;
this.branchService = branchService;
this.timeSeriesCreators = timeSeriesCreators;
}
public void index(@NotNull String repositoryUrl, @NotNull String branchName) throws GitAPIException, IOException {
Repository repository = repositoryRepository.findByUrl(repositoryUrl);
if (repository == null) {
repository = repositoryRepository.save(new Repository(repositoryUrl));
GitRepository gitRepository = gitRepositoryRepository.findByUrl(repositoryUrl);
if (gitRepository == null) {
gitRepository = gitRepositoryRepository.save(new GitRepository(repositoryUrl));
}
Branch branch = branchService.findByRepositoryAndName(repository, branchName);
Branch branch = branchService.findByRepositoryAndName(gitRepository, branchName);
if (branch == null) {
branch = new Branch(repository, branchName);
branch = new Branch(gitRepository, branchName);
}
branchService.save(branch, Collections.emptyList());
int commitsFrom = 0;
@ -56,6 +62,8 @@ public class IndexService {
commitsTo += COMMITS_PAGE_SIZE;
commits = gitRepositoryService.getCommits(repositoryUrl, branchName, commitsFrom, commitsTo, false);
}
Integer repositoryId = gitRepository.getId();
timeSeriesCreators.forEach(tsCreator -> tsCreator.addTimeSeries(repositoryId, branchName));
LOG.debug("Complete indexing {} branch", branchName);
}
}

@ -0,0 +1,116 @@
/*
* 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.service;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import ru.ulstu.extractor.http.HttpService;
import ru.ulstu.extractor.http.JsonTimeSeries;
import ru.ulstu.extractor.model.TimeSeries;
import ru.ulstu.extractor.model.TimeSeriesValue;
import ru.ulstu.extractor.repository.TimeSeriesRepository;
import ru.ulstu.extractor.repository.TimeSeriesValueRepository;
import ru.ulstu.extractor.ts.TimeSeriesDateMapper;
import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
@Service
public class TimeSeriesService {
private final static Logger LOG = LoggerFactory.getLogger(TimeSeriesService.class);
private final TimeSeriesRepository timeSeriesRepository;
private final TimeSeriesValueRepository timeSeriesValueRepository;
private final TimeSeriesDateMapper.TimeSeriesInterval timeSeriesInterval = TimeSeriesDateMapper.TimeSeriesInterval.HOUR;
private final HttpService httpService;
private final static String TIME_SERIES_SERVICE_URL = "http://time-series.athene.tech/api/1.0/add-time-series?setKey=git-extractor";
public TimeSeriesService(TimeSeriesRepository timeSeriesRepository,
TimeSeriesValueRepository timeSeriesValueRepository,
HttpService httpService) {
this.timeSeriesRepository = timeSeriesRepository;
this.timeSeriesValueRepository = timeSeriesValueRepository;
this.httpService = httpService;
}
/**
* Сохранить список временных рядов
*
* @param timeSeriesValues
* @return
*/
@Transactional
public List<TimeSeries> save(Map<String, List<TimeSeriesValue>> timeSeriesValues) {
List<TimeSeries> results = new ArrayList<>();
for (Map.Entry<String, List<TimeSeriesValue>> entry : timeSeriesValues.entrySet()) {
results.add(save(entry.getKey(), entry.getValue()));
}
return results;
}
@Transactional
public TimeSeries save(String timeSeriesName, List<TimeSeriesValue> timeSeriesValues) {
LOG.debug("Start save {} time series with {} time series values ", timeSeriesName, timeSeriesValues.size());
final TimeSeries timeSeries = findOrCreate(timeSeriesName);
List<TimeSeriesValue> timeSeriesValuesToRemove = timeSeries.getValues();
timeSeries.setValues(timeSeriesValues);
LOG.debug("Save time series {} ", timeSeries.getName());
TimeSeries savedTimeSeries = timeSeriesRepository.save(timeSeries);
LOG.debug("Clear {} time series values ", timeSeriesValuesToRemove.size());
timeSeriesValueRepository.deleteAll(timeSeriesValuesToRemove);
sendToTimeSeriesService(savedTimeSeries);
return savedTimeSeries;
}
public TimeSeries findOrCreate(String timeSeriesName) {
Optional<TimeSeries> maybeTimeSeries = timeSeriesRepository.findByName(timeSeriesName);
if (maybeTimeSeries.isPresent()) {
LOG.debug("TimeSeries {} exists.", maybeTimeSeries.get().getName());
return maybeTimeSeries.get();
}
return timeSeriesRepository.save(new TimeSeries(timeSeriesName));
}
public List<TimeSeriesValue> save(List<TimeSeriesValue> timeSeriesValues) {
return timeSeriesValues.stream()
.map(timeSeriesValue -> {
timeSeriesValue.setValue((timeSeriesValue.getValue()));
timeSeriesValue.setDate((timeSeriesValue.getDate()));
return timeSeriesValueRepository.save(timeSeriesValue);
}).collect(Collectors.toList());
}
public void addTimeSeriesValue(String timeSeriesName, Date date, Double value) {
LOG.debug("Start add time series values to {} time series values ", timeSeriesName);
TimeSeries timeSeries = findOrCreate(timeSeriesName);
timeSeriesValueRepository.save(new TimeSeriesValue(timeSeries, date, value));
}
public List<TimeSeriesValue> findAll() {
return timeSeriesValueRepository.findAll();
}
public TimeSeriesDateMapper.TimeSeriesInterval getTimeSeriesInterval() {
return timeSeriesInterval;
}
private void sendToTimeSeriesService(TimeSeries timeSeries) {
new Thread(() -> {
try {
httpService.post(TIME_SERIES_SERVICE_URL, new JSONObject(new JsonTimeSeries(timeSeries)));
LOG.debug("Успешно отправлен на сервис");
} catch (Exception ex) {
LOG.debug(ex.getMessage());
}
}).start();
}
}

@ -0,0 +1,40 @@
package ru.ulstu.extractor.ts;
import ru.ulstu.extractor.model.TimeSeriesValue;
import ru.ulstu.extractor.service.TimeSeriesService;
import java.util.List;
import java.util.Map;
import static ru.ulstu.extractor.ts.TimeSeriesDateMapper.mapTimeSeriesToInterval;
public abstract class AbstractTimeSeriesCreator {
public abstract String getTimeSeriesName();
/**
* Извлечь список точек временных рядов
*
* @param repositoryId
* @param branchName
* @return
*/
public abstract Map<String, List<TimeSeriesValue>> getTimeSeriesValues(Integer repositoryId, String branchName);
public abstract TimeSeriesService getTimeSeriesService();
/**
* Сохранить извлеченные временные ряды
*
* @param repositoryId
* @param branchName
*/
public void addTimeSeries(Integer repositoryId, String branchName) {
// извлеченные точки временных рядов
Map<String, List<TimeSeriesValue>> timeSeriesValues = getTimeSeriesValues(repositoryId, branchName);
// сгруппированные по временным интервалам точки временных рядов
timeSeriesValues.replaceAll((k, v) -> mapTimeSeriesToInterval(getTimeSeriesService().getTimeSeriesInterval(), v));
getTimeSeriesService().save(timeSeriesValues);
}
}

@ -0,0 +1,33 @@
package ru.ulstu.extractor.ts;
import org.springframework.stereotype.Component;
import ru.ulstu.extractor.model.TimeSeriesValue;
import ru.ulstu.extractor.service.TimeSeriesService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class AuthorTS extends AbstractTimeSeriesCreator {
private final TimeSeriesService timeSeriesService;
public AuthorTS(TimeSeriesService timeSeriesService) {
this.timeSeriesService = timeSeriesService;
}
@Override
public String getTimeSeriesName() {
return "Количество Авторов";
}
@Override
public Map<String, List<TimeSeriesValue>> getTimeSeriesValues(Integer repositoryId, String branchName) {
return new HashMap<>();
}
@Override
public TimeSeriesService getTimeSeriesService() {
return timeSeriesService;
}
}

@ -0,0 +1,33 @@
package ru.ulstu.extractor.ts;
import org.springframework.stereotype.Component;
import ru.ulstu.extractor.model.TimeSeriesValue;
import ru.ulstu.extractor.service.TimeSeriesService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class AuthorsCommentTS extends AbstractTimeSeriesCreator {
private final TimeSeriesService timeSeriesService;
public AuthorsCommentTS(TimeSeriesService timeSeriesService) {
this.timeSeriesService = timeSeriesService;
}
@Override
public String getTimeSeriesName() {
return "Количество коммитов авторов";
}
@Override
public Map<String, List<TimeSeriesValue>> getTimeSeriesValues(Integer repositoryId, String branchName) {
return new HashMap<>();
}
@Override
public TimeSeriesService getTimeSeriesService() {
return timeSeriesService;
}
}

@ -0,0 +1,33 @@
package ru.ulstu.extractor.ts;
import org.springframework.stereotype.Component;
import ru.ulstu.extractor.model.TimeSeriesValue;
import ru.ulstu.extractor.service.TimeSeriesService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class AuthorsCompletedIssueTS extends AbstractTimeSeriesCreator {
private final TimeSeriesService timeSeriesService;
public AuthorsCompletedIssueTS(TimeSeriesService timeSeriesService) {
this.timeSeriesService = timeSeriesService;
}
@Override
public String getTimeSeriesName() {
return "Количество выполненных issues авторов";
}
@Override
public Map<String, List<TimeSeriesValue>> getTimeSeriesValues(Integer repositoryId, String branchName) {
return new HashMap<>();
}
@Override
public TimeSeriesService getTimeSeriesService() {
return timeSeriesService;
}
}

@ -0,0 +1,33 @@
package ru.ulstu.extractor.ts;
import org.springframework.stereotype.Component;
import ru.ulstu.extractor.model.TimeSeriesValue;
import ru.ulstu.extractor.service.TimeSeriesService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class AuthorsIssueTS extends AbstractTimeSeriesCreator {
private final TimeSeriesService timeSeriesService;
public AuthorsIssueTS(TimeSeriesService timeSeriesService) {
this.timeSeriesService = timeSeriesService;
}
@Override
public String getTimeSeriesName() {
return "Количество issues авторов";
}
@Override
public Map<String, List<TimeSeriesValue>> getTimeSeriesValues(Integer repositoryId, String branchName) {
return new HashMap<>();
}
@Override
public TimeSeriesService getTimeSeriesService() {
return timeSeriesService;
}
}

@ -0,0 +1,33 @@
package ru.ulstu.extractor.ts;
import org.springframework.stereotype.Component;
import ru.ulstu.extractor.model.TimeSeriesValue;
import ru.ulstu.extractor.service.TimeSeriesService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class BranchTS extends AbstractTimeSeriesCreator {
private final TimeSeriesService timeSeriesService;
public BranchTS(TimeSeriesService timeSeriesService) {
this.timeSeriesService = timeSeriesService;
}
@Override
public String getTimeSeriesName() {
return "Количество веток";
}
@Override
public Map<String, List<TimeSeriesValue>> getTimeSeriesValues(Integer repositoryId, String branchName) {
return new HashMap<>();
}
@Override
public TimeSeriesService getTimeSeriesService() {
return timeSeriesService;
}
}

@ -0,0 +1,33 @@
package ru.ulstu.extractor.ts;
import org.springframework.stereotype.Component;
import ru.ulstu.extractor.model.TimeSeriesValue;
import ru.ulstu.extractor.service.TimeSeriesService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class ClassTS extends AbstractTimeSeriesCreator {
private final TimeSeriesService timeSeriesService;
public ClassTS(TimeSeriesService timeSeriesService) {
this.timeSeriesService = timeSeriesService;
}
@Override
public String getTimeSeriesName() {
return "Количество классов";
}
@Override
public Map<String, List<TimeSeriesValue>> getTimeSeriesValues(Integer repositoryId, String branchName) {
return new HashMap<>();
}
@Override
public TimeSeriesService getTimeSeriesService() {
return timeSeriesService;
}
}

@ -0,0 +1,45 @@
package ru.ulstu.extractor.ts;
import org.springframework.stereotype.Component;
import ru.ulstu.extractor.commit.service.CommitService;
import ru.ulstu.extractor.model.TimeSeriesValue;
import ru.ulstu.extractor.service.TimeSeriesService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
public class CommitsTS extends AbstractTimeSeriesCreator {
private final TimeSeriesService timeSeriesService;
private final CommitService commitService;
public CommitsTS(TimeSeriesService timeSeriesService,
CommitService commitService) {
this.timeSeriesService = timeSeriesService;
this.commitService = commitService;
}
@Override
public String getTimeSeriesName() {
return "Количество коммитов во времени";
}
@Override
public Map<String, List<TimeSeriesValue>> getTimeSeriesValues(Integer repositoryId, String branchName) {
//TODO: добавить постраничное чтение
Map<String, List<TimeSeriesValue>> result = new HashMap<>();
result.put(String.format("%s %s %s", getTimeSeriesName(), repositoryId, branchName),
commitService.findByRepositoryIdAndName(repositoryId, branchName)
.stream()
.map(c -> new TimeSeriesValue(c.getDate(), 1.0))
.collect(Collectors.toList()));
return result;
}
@Override
public TimeSeriesService getTimeSeriesService() {
return timeSeriesService;
}
}

@ -0,0 +1,33 @@
package ru.ulstu.extractor.ts;
import org.springframework.stereotype.Component;
import ru.ulstu.extractor.model.TimeSeriesValue;
import ru.ulstu.extractor.service.TimeSeriesService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class DependenceTS extends AbstractTimeSeriesCreator {
private final TimeSeriesService timeSeriesService;
public DependenceTS(TimeSeriesService timeSeriesService) {
this.timeSeriesService = timeSeriesService;
}
@Override
public String getTimeSeriesName() {
return "Количество зависимостей";
}
@Override
public Map<String, List<TimeSeriesValue>> getTimeSeriesValues(Integer repositoryId, String branchName) {
return new HashMap<>();
}
@Override
public TimeSeriesService getTimeSeriesService() {
return timeSeriesService;
}
}

@ -0,0 +1,33 @@
package ru.ulstu.extractor.ts;
import org.springframework.stereotype.Component;
import ru.ulstu.extractor.model.TimeSeriesValue;
import ru.ulstu.extractor.service.TimeSeriesService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class EntityTS extends AbstractTimeSeriesCreator {
private final TimeSeriesService timeSeriesService;
public EntityTS(TimeSeriesService timeSeriesService) {
this.timeSeriesService = timeSeriesService;
}
@Override
public String getTimeSeriesName() {
return "Количество сущностей";
}
@Override
public Map<String, List<TimeSeriesValue>> getTimeSeriesValues(Integer repositoryId, String branchName) {
return new HashMap<>();
}
@Override
public TimeSeriesService getTimeSeriesService() {
return timeSeriesService;
}
}

@ -0,0 +1,33 @@
package ru.ulstu.extractor.ts;
import org.springframework.stereotype.Component;
import ru.ulstu.extractor.model.TimeSeriesValue;
import ru.ulstu.extractor.service.TimeSeriesService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class FileTS extends AbstractTimeSeriesCreator {
private final TimeSeriesService timeSeriesService;
public FileTS(TimeSeriesService timeSeriesService) {
this.timeSeriesService = timeSeriesService;
}
@Override
public String getTimeSeriesName() {
return "Количество файлов";
}
@Override
public Map<String, List<TimeSeriesValue>> getTimeSeriesValues(Integer repositoryId, String branchName) {
return new HashMap<>();
}
@Override
public TimeSeriesService getTimeSeriesService() {
return timeSeriesService;
}
}

@ -0,0 +1,33 @@
package ru.ulstu.extractor.ts;
import org.springframework.stereotype.Component;
import ru.ulstu.extractor.model.TimeSeriesValue;
import ru.ulstu.extractor.service.TimeSeriesService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class InterfaceTS extends AbstractTimeSeriesCreator {
private final TimeSeriesService timeSeriesService;
public InterfaceTS(TimeSeriesService timeSeriesService) {
this.timeSeriesService = timeSeriesService;
}
@Override
public String getTimeSeriesName() {
return "Количество интерфейсов";
}
@Override
public Map<String, List<TimeSeriesValue>> getTimeSeriesValues(Integer repositoryId, String branchName) {
return new HashMap<>();
}
@Override
public TimeSeriesService getTimeSeriesService() {
return timeSeriesService;
}
}

@ -0,0 +1,33 @@
package ru.ulstu.extractor.ts;
import org.springframework.stereotype.Component;
import ru.ulstu.extractor.model.TimeSeriesValue;
import ru.ulstu.extractor.service.TimeSeriesService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class IssuesTS extends AbstractTimeSeriesCreator {
private final TimeSeriesService timeSeriesService;
public IssuesTS(TimeSeriesService timeSeriesService) {
this.timeSeriesService = timeSeriesService;
}
@Override
public String getTimeSeriesName() {
return "Количество issues созданных во времени";
}
@Override
public Map<String, List<TimeSeriesValue>> getTimeSeriesValues(Integer repositoryId, String branchName) {
return new HashMap<>();
}
@Override
public TimeSeriesService getTimeSeriesService() {
return timeSeriesService;
}
}

@ -0,0 +1,33 @@
package ru.ulstu.extractor.ts;
import org.springframework.stereotype.Component;
import ru.ulstu.extractor.model.TimeSeriesValue;
import ru.ulstu.extractor.service.TimeSeriesService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class ProcessTS extends AbstractTimeSeriesCreator {
private final TimeSeriesService timeSeriesService;
public ProcessTS(TimeSeriesService timeSeriesService) {
this.timeSeriesService = timeSeriesService;
}
@Override
public String getTimeSeriesName() {
return "Количество процессов";
}
@Override
public Map<String, List<TimeSeriesValue>> getTimeSeriesValues(Integer repositoryId, String branchName) {
return new HashMap<>();
}
@Override
public TimeSeriesService getTimeSeriesService() {
return timeSeriesService;
}
}

@ -0,0 +1,33 @@
package ru.ulstu.extractor.ts;
import org.springframework.stereotype.Component;
import ru.ulstu.extractor.model.TimeSeriesValue;
import ru.ulstu.extractor.service.TimeSeriesService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class StarTS extends AbstractTimeSeriesCreator {
private final TimeSeriesService timeSeriesService;
public StarTS(TimeSeriesService timeSeriesService) {
this.timeSeriesService = timeSeriesService;
}
@Override
public String getTimeSeriesName() {
return "Количество звезд";
}
@Override
public Map<String, List<TimeSeriesValue>> getTimeSeriesValues(Integer repositoryId, String branchName) {
return new HashMap<>();
}
@Override
public TimeSeriesService getTimeSeriesService() {
return timeSeriesService;
}
}

@ -0,0 +1,64 @@
package ru.ulstu.extractor.ts;
import org.apache.commons.lang3.time.DateUtils;
import ru.ulstu.extractor.model.TimeSeries;
import ru.ulstu.extractor.model.TimeSeriesValue;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Класс для регулировки дискретности временного ряда.
* Можно создать временной ряд с точками с секундными отметками, затем суммировать значения,
* применив одно из значений TimeSeriesInterval
*/
public class TimeSeriesDateMapper {
public static List<TimeSeriesValue> mapTimeSeriesToInterval(TimeSeriesInterval timeSeriesInterval, List<TimeSeriesValue> timeSeriesValues) {
List<TimeSeriesValue> trimmedTimeSeriesValues = timeSeriesValues
.stream()
.map(timeSeriesValue -> new TimeSeriesValue(trimTo(timeSeriesInterval, timeSeriesValue.getDate()),
timeSeriesValue.getValue()))
.collect(Collectors.toList());
Map<Date, Double> groupedTimeSeriesValues = trimmedTimeSeriesValues
.stream()
.collect(Collectors.groupingBy(TimeSeriesValue::getDate,
Collectors.summingDouble(TimeSeriesValue::getValue)));
return groupedTimeSeriesValues.entrySet()
.stream()
.map(e -> new TimeSeriesValue(e.getKey(), e.getValue()))
.collect(Collectors.toList());
}
public static TimeSeries mapTimeSeriesToInterval(TimeSeriesInterval timeSeriesInterval, TimeSeries timeSeries) {
timeSeries.setValues(mapTimeSeriesToInterval(timeSeriesInterval, timeSeries.getValues()));
return timeSeries;
}
private static Date trimTo(TimeSeriesInterval timeSeriesInterval, Date date) {
return DateUtils.truncate(date, timeSeriesInterval.calendarField);
}
/**
* Интервальность временного ряда при преобразовании
*/
public enum TimeSeriesInterval {
SECOND(Calendar.SECOND),
MINUTE(Calendar.MINUTE),
HOUR(Calendar.HOUR_OF_DAY),
DAY(Calendar.DAY_OF_MONTH),
WEEK(Calendar.WEEK_OF_MONTH),
MONTH(Calendar.MONTH),
YEAR(Calendar.YEAR);
private final int calendarField;
TimeSeriesInterval(int calendarField) {
this.calendarField = calendarField;
}
}
}

@ -0,0 +1,44 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet author="orion" id="20220422-120000-1">
<createTable tableName="time_series">
<column name="id" type="integer">
<constraints nullable="false"/>
</column>
<column name="name" type="varchar(255)">
<constraints nullable="false"/>
</column>
</createTable>
<addPrimaryKey columnNames="id" constraintName="pk_time_series" tableName="time_series"/>
<createTable tableName="time_series_value">
<column name="id" type="integer">
<constraints nullable="false"/>
</column>
<column name="time_series_id" type="integer">
<constraints nullable="false"/>
</column>
<column name="date" type="timestamp">
<constraints nullable="false"/>
</column>
<column name="value" type="integer">
<constraints nullable="false"/>
</column>
</createTable>
<addPrimaryKey columnNames="id" constraintName="pk_time_series_value" tableName="time_series_value"/>
<addForeignKeyConstraint baseTableName="time_series_value" baseColumnNames="time_series_id"
constraintName="fk_time_series"
referencedTableName="time_series"
referencedColumnNames="id"/>
</changeSet>
<changeSet author="orion" id="20220422-120000-2">
<addColumn tableName="time_series">
<column name="version" type="integer"/>
</addColumn>
<addColumn tableName="time_series_value">
<column name="version" type="integer"/>
</addColumn>
</changeSet>
</databaseChangeLog>

@ -0,0 +1,23 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet author="orion" id="20220621-120000-1">
<renameColumn tableName="branch" oldColumnName="repository_id" newColumnName="git_repository_id"/>
</changeSet>
<changeSet author="orion" id="20220621-120000-2">
<renameTable oldTableName="repository" newTableName="git_repository"/>
</changeSet>
<changeSet author="orion" id="20221006-120000-1">
<dropNotNullConstraint tableName="time_series_value" columnName="time_series_id"/>
</changeSet>
<changeSet author="orion" id="20221006-120000-2">
<delete tableName="time_series_value"/>
<dropColumn tableName="time_series_value" columnName="value"/>
<addColumn tableName="time_series_value">
<column name="value" type="double">
<constraints nullable="false"/>
</column>
</addColumn>
</changeSet>
</databaseChangeLog>

@ -12,4 +12,6 @@
<include file="db/changelog-20210326_170000-schema.xml"/>
<include file="db/changelog-20210329_120000-schema.xml"/>
<include file="db/changelog-20210412_100000-schema.xml"/>
<include file="db/changelog-20220422_120000-schema.xml"/>
<include file="db/changelog-20220621_120000-schema.xml"/>
</databaseChangeLog>

@ -193,7 +193,7 @@
<option value="">Все ветки</option>
<option th:each="branch : ${branches}"
th:value="${branch.id}"
th:utext="${branch.repository.url} + ' - '+ ${branch.name}">
th:utext="${branch.gitRepository.url} + ' - '+ ${branch.name}">
</option>
</select>
<script th:inline="javascript">

@ -0,0 +1,103 @@
package ru.ulstu;
import org.junit.Assert;
import org.junit.Test;
import ru.ulstu.extractor.model.TimeSeries;
import ru.ulstu.extractor.model.TimeSeriesValue;
import ru.ulstu.extractor.ts.TimeSeriesDateMapper;
import java.util.Arrays;
import java.util.Calendar;
import java.util.GregorianCalendar;
public class TimeSeriesMapperTest {
@Test
public void testMappingByDay() {
Calendar c1 = GregorianCalendar.getInstance();
c1.set(2020, 5, 1, 1, 1, 1);
Calendar c2 = GregorianCalendar.getInstance();
c2.set(2020, 5, 2, 2, 1, 1);
TimeSeries timeSeries = new TimeSeries("Тестовый",
Arrays.asList(new TimeSeriesValue(c1.getTime(), 10),
new TimeSeriesValue(c2.getTime(), 10)));
TimeSeriesDateMapper mapper = new TimeSeriesDateMapper();
timeSeries = mapper.mapTimeSeriesToInterval(TimeSeriesDateMapper.TimeSeriesInterval.MONTH, timeSeries);
Assert.assertEquals(1, timeSeries.getValues().size());
Assert.assertEquals(Integer.valueOf(20), timeSeries.getValues().get(0).getValue());
}
@Test
public void testMappingByDayDifferent() {
Calendar c1 = GregorianCalendar.getInstance();
c1.set(2020, 5, 1, 1, 1, 1);
Calendar c2 = GregorianCalendar.getInstance();
c2.set(2020, 5, 2, 1, 1, 1);
TimeSeries timeSeries = new TimeSeries("Тестовый",
Arrays.asList(new TimeSeriesValue(c1.getTime(), 10),
new TimeSeriesValue(c2.getTime(), 10)));
TimeSeriesDateMapper mapper = new TimeSeriesDateMapper();
timeSeries = mapper.mapTimeSeriesToInterval(TimeSeriesDateMapper.TimeSeriesInterval.MONTH, timeSeries);
Assert.assertEquals(1, timeSeries.getValues().size());
Assert.assertEquals(Integer.valueOf(20), timeSeries.getValues().get(0).getValue());
}
@Test
public void testMappingByMonth() {
Calendar c1 = GregorianCalendar.getInstance();
c1.set(2020, 5, 1, 1, 1, 1);
Calendar c2 = GregorianCalendar.getInstance();
c2.set(2020, 5, 2, 1, 1, 1);
TimeSeries timeSeries = new TimeSeries("Тестовый",
Arrays.asList(new TimeSeriesValue(c1.getTime(), 10),
new TimeSeriesValue(c2.getTime(), 10)));
TimeSeriesDateMapper mapper = new TimeSeriesDateMapper();
timeSeries = mapper.mapTimeSeriesToInterval(TimeSeriesDateMapper.TimeSeriesInterval.MONTH, timeSeries);
Assert.assertEquals(1, timeSeries.getValues().size());
Assert.assertEquals(Integer.valueOf(20), timeSeries.getValues().get(0).getValue());
}
@Test
public void testMappingByMonthDifferent() {
Calendar c1 = GregorianCalendar.getInstance();
c1.set(2020, 5, 1, 1, 1, 1);
Calendar c2 = GregorianCalendar.getInstance();
c2.set(2020, 6, 2, 1, 1, 1);
TimeSeries timeSeries = new TimeSeries("Тестовый",
Arrays.asList(new TimeSeriesValue(c1.getTime(), 10),
new TimeSeriesValue(c2.getTime(), 10)));
TimeSeriesDateMapper mapper = new TimeSeriesDateMapper();
timeSeries = mapper.mapTimeSeriesToInterval(TimeSeriesDateMapper.TimeSeriesInterval.MONTH, timeSeries);
Assert.assertEquals(2, timeSeries.getValues().size());
Assert.assertEquals(Integer.valueOf(10), timeSeries.getValues().get(0).getValue());
}
@Test
public void testMappingByYear() {
Calendar c1 = GregorianCalendar.getInstance();
c1.set(2020, 5, 1, 1, 1, 1);
Calendar c2 = GregorianCalendar.getInstance();
c2.set(2020, 5, 2, 1, 1, 1);
TimeSeries timeSeries = new TimeSeries("Тестовый",
Arrays.asList(new TimeSeriesValue(c1.getTime(), 10),
new TimeSeriesValue(c2.getTime(), 10)));
TimeSeriesDateMapper mapper = new TimeSeriesDateMapper();
timeSeries = mapper.mapTimeSeriesToInterval(TimeSeriesDateMapper.TimeSeriesInterval.YEAR, timeSeries);
Assert.assertEquals(1, timeSeries.getValues().size());
Assert.assertEquals(Integer.valueOf(20), timeSeries.getValues().get(0).getValue());
}
@Test
public void testMappingByYearDifferent() {
Calendar c1 = GregorianCalendar.getInstance();
c1.set(2020, 5, 1, 1, 1, 1);
Calendar c2 = GregorianCalendar.getInstance();
c2.set(2021, 5, 2, 1, 1, 1);
TimeSeries timeSeries = new TimeSeries("Тестовый",
Arrays.asList(new TimeSeriesValue(c1.getTime(), 10),
new TimeSeriesValue(c2.getTime(), 10)));
TimeSeriesDateMapper mapper = new TimeSeriesDateMapper();
timeSeries = mapper.mapTimeSeriesToInterval(TimeSeriesDateMapper.TimeSeriesInterval.YEAR, timeSeries);
Assert.assertEquals(2, timeSeries.getValues().size());
Assert.assertEquals(Integer.valueOf(10), timeSeries.getValues().get(0).getValue());
}
}
Loading…
Cancel
Save