From db205a2c6736e41699c240287cc9ba72e56dcedb Mon Sep 17 00:00:00 2001
From: Yaroslav Svitlytskyi <53532703+YarikRevich@users.noreply.github.com>
Date: Thu, 10 Oct 2024 03:14:26 +0200
Subject: [PATCH] fix: fixed repository download (#28)
---
.github/workflows/build.yml | 2 +-
api-server/pom.xml | 14 +-
.../dto/GitHubRepositoriesDto.java | 30 +++
.../com/repoachiever/dto/GitHubUserDto.java | 22 ++
.../entity/common/ConfigEntity.java | 6 -
.../entity/common/PropertiesEntity.java | 9 +
...nfigCronExpressionValidationException.java | 22 ++
.../client/github/IGitHubClientService.java | 10 +-
.../service/cluster/facade/ClusterFacade.java | 2 -
.../service/config/ConfigService.java | 41 +--
.../common/VendorConfigurationHelper.java | 5 +-
.../git/github/GitGitHubVendorService.java | 91 +++++--
.../service/workspace/WorkspaceService.java | 2 +-
.../src/main/resources/application.properties | 9 +
.../com/repoachiever/entity/ConfigEntity.java | 5 -
...nfigCronExpressionValidationException.java | 22 ++
.../service/config/ConfigService.java | 8 +
.../scheduler/SchedulerConfigService.java | 89 ++++---
.../service/state/StateService.java | 43 +---
.../common/VendorConfigurationHelper.java | 5 +-
.../git/github/GitGitHubVendorService.java | 4 +
.../service/element/list/ListVisualizer.java | 233 +++++++++---------
pom.xml | 5 +
samples/config/api-server/api-server.yaml | 2 +-
24 files changed, 441 insertions(+), 240 deletions(-)
create mode 100644 api-server/src/main/java/com/repoachiever/dto/GitHubRepositoriesDto.java
create mode 100644 api-server/src/main/java/com/repoachiever/dto/GitHubUserDto.java
create mode 100644 api-server/src/main/java/com/repoachiever/exception/ConfigCronExpressionValidationException.java
create mode 100644 cluster/src/main/java/com/repoachiever/exception/ConfigCronExpressionValidationException.java
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 8988936..44b8f1c 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -9,7 +9,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- - name: Set up JDK 23
+ - name: "Set up JDK 23"
uses: oracle-actions/setup-java@v1
with:
website: oracle.com
diff --git a/api-server/pom.xml b/api-server/pom.xml
index 35e81e3..f3105e7 100644
--- a/api-server/pom.xml
+++ b/api-server/pom.xml
@@ -1,7 +1,7 @@
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
api-server
1.0-SNAPSHOT
@@ -104,6 +104,10 @@
org.jboss.logging
jboss-logging
+
+ org.jboss.logmanager
+ log4j2-jboss-logmanager
+
jakarta.json
jakarta.json-api
@@ -236,7 +240,9 @@
file=byte[]
- @lombok.Data @lombok.NoArgsConstructor @lombok.AllArgsConstructor(staticName = "of")
+ @lombok.Data
+ @lombok.NoArgsConstructor @lombok.AllArgsConstructor(staticName
+ = "of")
src/main/java
true
true
@@ -322,4 +328,4 @@
-
+
\ No newline at end of file
diff --git a/api-server/src/main/java/com/repoachiever/dto/GitHubRepositoriesDto.java b/api-server/src/main/java/com/repoachiever/dto/GitHubRepositoriesDto.java
new file mode 100644
index 0000000..faf9bf1
--- /dev/null
+++ b/api-server/src/main/java/com/repoachiever/dto/GitHubRepositoriesDto.java
@@ -0,0 +1,30 @@
+package com.repoachiever.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+
+/**
+ * Represents retrieved GitHub repository details.
+ */
+@Getter
+@ApplicationScoped
+public class GitHubRepositoriesDto {
+ /**
+ * Represents remote repository short name.
+ */
+ @Valid
+ @NotNull
+ @JsonProperty("name")
+ public String name;
+
+ /**
+ * Represents remote repository default branch.
+ */
+ @Valid
+ @NotNull
+ @JsonProperty("default_branch")
+ public String defaultBranch;
+}
\ No newline at end of file
diff --git a/api-server/src/main/java/com/repoachiever/dto/GitHubUserDto.java b/api-server/src/main/java/com/repoachiever/dto/GitHubUserDto.java
new file mode 100644
index 0000000..449a4aa
--- /dev/null
+++ b/api-server/src/main/java/com/repoachiever/dto/GitHubUserDto.java
@@ -0,0 +1,22 @@
+package com.repoachiever.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+
+/**
+ * Represents retrieved GitHub user details.
+ */
+@Getter
+@ApplicationScoped
+public class GitHubUserDto {
+ /**
+ * Represents user name.
+ */
+ @Valid
+ @NotNull
+ @JsonProperty("login")
+ public String login;
+}
\ No newline at end of file
diff --git a/api-server/src/main/java/com/repoachiever/entity/common/ConfigEntity.java b/api-server/src/main/java/com/repoachiever/entity/common/ConfigEntity.java
index 2cab6b1..f0bcad2 100644
--- a/api-server/src/main/java/com/repoachiever/entity/common/ConfigEntity.java
+++ b/api-server/src/main/java/com/repoachiever/entity/common/ConfigEntity.java
@@ -5,7 +5,6 @@
import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
-import jakarta.validation.constraints.Pattern;
import lombok.Getter;
/**
@@ -189,11 +188,6 @@ public static class Cluster {
@Getter
public static class Worker {
@NotNull
- @Pattern(
- regexp =
- "(((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?)|(([\\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9]))|([\\?])|([\\*]))[\\s](((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?)|(([\\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9]))|([\\?])|([\\*]))[\\s](((([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?,)*([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?)|(([\\*]|[0-9]|[0-1][0-9]|[2][0-3])/([0-9]|[0-1][0-9]|[2][0-3]))|([\\?])|([\\*]))[\\s](((([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?,)*([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?(C)?)|(([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])/([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(C)?)|(L(-[0-9])?)|(L(-[1-2][0-9])?)|(L(-[3][0-1])?)|(LW)|([1-9]W)|([1-3][0-9]W)|([\\?])|([\\*]))[\\s](((([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?,)*([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?)|(([1-9]|0[1-9]|1[0-2])/([1-9]|0[1-9]|1[0-2]))|(((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?,)*(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?)|((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)/(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))|([\\?])|([\\*]))[\\s]((([1-7](-([1-7]))?,)*([1-7])(-([1-7]))?)|([1-7]/([1-7]))|(((MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?,)*(MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?(C)?)|((MON|TUE|WED|THU|FRI|SAT|SUN)/(MON|TUE|WED|THU|FRI|SAT|SUN)(C)?)|(([1-7]|(MON|TUE|WED|THU|FRI|SAT|SUN))?(L|LW)?)|(([1-7]|MON|TUE|WED|THU|FRI|SAT|SUN)#([1-7])?)|([\\?])|([\\*]))([\\s]?(([\\*])?|(19[7-9][0-9])|(20[0-9][0-9]))?|"
- + " (((19[7-9][0-9])|(20[0-9][0-9]))/((19[7-9][0-9])|(20[0-9][0-9])))?|"
- + " ((((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?,)*((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?)?)")
@JsonProperty("frequency")
public String frequency;
}
diff --git a/api-server/src/main/java/com/repoachiever/entity/common/PropertiesEntity.java b/api-server/src/main/java/com/repoachiever/entity/common/PropertiesEntity.java
index 8092225..d3085ec 100644
--- a/api-server/src/main/java/com/repoachiever/entity/common/PropertiesEntity.java
+++ b/api-server/src/main/java/com/repoachiever/entity/common/PropertiesEntity.java
@@ -23,6 +23,15 @@ public class PropertiesEntity {
@ConfigProperty(name = "quarkus.rest-client.github.url")
String restClientGitHubUrl;
+ @ConfigProperty(name = "rest-client.github.page-size")
+ Integer restClientGitHubPageSize;
+
+ @ConfigProperty(name = "rest-client.github.max-page")
+ Integer restClientGitHubMaxPage;
+
+ @ConfigProperty(name = "rest-client.github.repo-visibility")
+ String restClientGitHubRepoVisibility;
+
@ConfigProperty(name = "github.location.notation")
String gitHubLocationNotation;
diff --git a/api-server/src/main/java/com/repoachiever/exception/ConfigCronExpressionValidationException.java b/api-server/src/main/java/com/repoachiever/exception/ConfigCronExpressionValidationException.java
new file mode 100644
index 0000000..6c30c94
--- /dev/null
+++ b/api-server/src/main/java/com/repoachiever/exception/ConfigCronExpressionValidationException.java
@@ -0,0 +1,22 @@
+package com.repoachiever.exception;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Formatter;
+
+/**
+ * Represents exception used when configuration file cron expression validation
+ * process fails.
+ */
+public class ConfigCronExpressionValidationException extends IOException {
+ public ConfigCronExpressionValidationException() {
+ this("");
+ }
+
+ public ConfigCronExpressionValidationException(Object... message) {
+ super(
+ new Formatter()
+ .format("Config file cron expression is not valid: %s", Arrays.stream(message).toArray())
+ .toString());
+ }
+}
diff --git a/api-server/src/main/java/com/repoachiever/service/client/github/IGitHubClientService.java b/api-server/src/main/java/com/repoachiever/service/client/github/IGitHubClientService.java
index 084cdba..d798203 100644
--- a/api-server/src/main/java/com/repoachiever/service/client/github/IGitHubClientService.java
+++ b/api-server/src/main/java/com/repoachiever/service/client/github/IGitHubClientService.java
@@ -4,6 +4,7 @@
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
@@ -24,12 +25,13 @@ public interface IGitHubClientService {
Response getPermissionScopes(@HeaderParam(HttpHeaders.AUTHORIZATION) String token);
@GET
- @Path("/repos/{owner}/{name}}")
+ @Path("/user/repos")
@Produces(MediaType.APPLICATION_JSON)
- Response getRepository(
+ Response getRepositories(
@HeaderParam(HttpHeaders.AUTHORIZATION) String token,
- @PathParam("owner") String owner,
- @PathParam("name") String name);
+ @QueryParam("per_page") Integer perPage,
+ @QueryParam("page") Integer page,
+ @QueryParam("visibility") String visibility);
@GET
@Path("/repos/{owner}/{name}/branches/{branch}")
diff --git a/api-server/src/main/java/com/repoachiever/service/cluster/facade/ClusterFacade.java b/api-server/src/main/java/com/repoachiever/service/cluster/facade/ClusterFacade.java
index 1a0d902..209d61e 100644
--- a/api-server/src/main/java/com/repoachiever/service/cluster/facade/ClusterFacade.java
+++ b/api-server/src/main/java/com/repoachiever/service/cluster/facade/ClusterFacade.java
@@ -367,8 +367,6 @@ public void destroy(ContentWithdrawal contentWithdrawal) throws ClusterWithdrawa
logger.info(
String.format("Removing RepoAchiever Cluster allocation: '%s'", clusterAllocation.getName()));
- System.out.println(clusterAllocation.getPid());
-
try {
clusterService.destroy(clusterAllocation.getPid());
} catch (ClusterDestructionFailureException e) {
diff --git a/api-server/src/main/java/com/repoachiever/service/config/ConfigService.java b/api-server/src/main/java/com/repoachiever/service/config/ConfigService.java
index fc32c0e..025bfed 100644
--- a/api-server/src/main/java/com/repoachiever/service/config/ConfigService.java
+++ b/api-server/src/main/java/com/repoachiever/service/config/ConfigService.java
@@ -8,6 +8,7 @@
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.repoachiever.entity.common.ConfigEntity;
import com.repoachiever.entity.common.PropertiesEntity;
+import com.repoachiever.exception.ConfigCronExpressionValidationException;
import com.repoachiever.exception.ConfigFileClosureFailureException;
import com.repoachiever.exception.ConfigFileNotFoundException;
import com.repoachiever.exception.ConfigFileReadingFailureException;
@@ -28,11 +29,14 @@
import java.util.stream.Collectors;
import lombok.Getter;
+
+import org.apache.logging.log4j.core.util.CronExpression;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
- * Service used to perform RepoAchiever API Server configuration processing operation.
+ * Service used to perform RepoAchiever API Server configuration processing
+ * operation.
*/
@Startup
@ApplicationScoped
@@ -44,16 +48,19 @@ public class ConfigService {
private ConfigEntity config;
/**
- * Reads configuration from the opened configuration file using mapping with a configuration entity.
+ * Reads configuration from the opened configuration file using mapping with a
+ * configuration entity.
*
- * @throws ConfigFileNotFoundException if configuration file is not found.
- * @throws ConfigValidationException if configuration file operation failed.
- * @throws ConfigFileReadingFailureException if configuration file reading operation failed.
- * @throws ConfigFileClosureFailureException if configuration file closure operation failed.
+ * @throws ConfigFileNotFoundException if configuration file is not found.
+ * @throws ConfigValidationException if configuration file operation
+ * failed.
+ * @throws ConfigFileReadingFailureException if configuration file reading
+ * operation failed.
+ * @throws ConfigFileClosureFailureException if configuration file closure
+ * operation failed.
*/
@PostConstruct
- private void configure() throws
- ConfigFileNotFoundException,
+ private void configure() throws ConfigFileNotFoundException,
ConfigValidationException,
ConfigFileReadingFailureException,
ConfigFileClosureFailureException {
@@ -66,11 +73,10 @@ private void configure() throws
throw new ConfigFileNotFoundException(e.getMessage());
}
- ObjectMapper mapper =
- new ObjectMapper(new YAMLFactory())
- .configure(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES, true)
- .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true)
- .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
+ ObjectMapper mapper = new ObjectMapper(new YAMLFactory())
+ .configure(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES, true)
+ .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true)
+ .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
ObjectReader reader = mapper.reader().forType(new TypeReference() {
});
@@ -89,8 +95,7 @@ private void configure() throws
try (ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory()) {
Validator validator = validatorFactory.getValidator();
- Set> validationResult =
- validator.validate(config);
+ Set> validationResult = validator.validate(config);
if (!validationResult.isEmpty()) {
throw new ConfigValidationException(
@@ -99,6 +104,12 @@ private void configure() throws
.collect(Collectors.joining(", ")));
}
}
+
+ if (!CronExpression.isValidExpression(
+ config.getResource().getWorker().getFrequency())) {
+ throw new ConfigValidationException(
+ new ConfigCronExpressionValidationException().getMessage());
+ }
} finally {
try {
file.close();
diff --git a/api-server/src/main/java/com/repoachiever/service/vendor/common/VendorConfigurationHelper.java b/api-server/src/main/java/com/repoachiever/service/vendor/common/VendorConfigurationHelper.java
index cfa415c..cdadd88 100644
--- a/api-server/src/main/java/com/repoachiever/service/vendor/common/VendorConfigurationHelper.java
+++ b/api-server/src/main/java/com/repoachiever/service/vendor/common/VendorConfigurationHelper.java
@@ -9,6 +9,7 @@
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -44,7 +45,9 @@ public GitHubLocationNotationDto parseLocationGitHubNotation(String location) {
matcher.find();
- if (matcher.groupCount() == 4) {
+ String optionalMatch = matcher.group(4);
+
+ if (matcher.groupCount() == 4 && Objects.nonNull(optionalMatch)) {
return GitHubLocationNotationDto.of(
matcher.group(1),
matcher.group(2),
diff --git a/api-server/src/main/java/com/repoachiever/service/vendor/git/github/GitGitHubVendorService.java b/api-server/src/main/java/com/repoachiever/service/vendor/git/github/GitGitHubVendorService.java
index 8bba7f9..5b516f9 100644
--- a/api-server/src/main/java/com/repoachiever/service/vendor/git/github/GitGitHubVendorService.java
+++ b/api-server/src/main/java/com/repoachiever/service/vendor/git/github/GitGitHubVendorService.java
@@ -1,32 +1,77 @@
package com.repoachiever.service.vendor.git.github;
+import com.repoachiever.dto.GitHubRepositoriesDto;
+import com.repoachiever.dto.GitHubUserDto;
+import com.repoachiever.entity.common.PropertiesEntity;
import com.repoachiever.dto.GitHubLocationNotationDto;
import com.repoachiever.service.client.github.IGitHubClientService;
import com.repoachiever.service.vendor.common.VendorConfigurationHelper;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.GenericType;
import jakarta.ws.rs.core.Response;
import org.apache.http.HttpStatus;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* Service used to represent GitHub external service operations.
*/
@ApplicationScoped
public class GitGitHubVendorService {
+ @Inject
+ PropertiesEntity properties;
+
@Inject
@RestClient
IGitHubClientService gitHubClientService;
+ /**
+ * Retrieves repositories of all types for the provided user.
+ *
+ * @param token given access token.
+ * @return retrieved user repositories of all types.
+ */
+ private List getRepositories(String token) {
+ List result = new ArrayList();
+
+ Response response;
+
+ for (Integer page = 1; page < properties.getRestClientGitHubMaxPage(); page++) {
+ response = gitHubClientService.getRepositories(
+ token,
+ properties.getRestClientGitHubPageSize(),
+ page,
+ properties.getRestClientGitHubRepoVisibility());
+
+ if (response.getStatus() != HttpStatus.SC_OK) {
+ return null;
+ }
+
+ List part = response
+ .readEntity(new GenericType>() {
+ });
+
+ if (part.isEmpty()) {
+ break;
+ }
+
+ result.addAll(part);
+ }
+
+ return result;
+ };
+
/**
* Checks if the given token is valid.
*
- * @param token given token to be validated.
+ * @param token given access token to be validated.
* @return result of the check.
*/
public Boolean isTokenValid(String token) {
@@ -48,35 +93,41 @@ public Boolean isTokenValid(String token) {
* @return result of the check.
*/
public Boolean areLocationsValid(String token, List locations) {
+ List repositories = getRepositories(token);
+
+ if (Objects.isNull(repositories)) {
+ return false;
+ }
+
return locations
.stream()
- .allMatch(element -> {
- try {
- Response response;
+ .allMatch(e1 -> {
+ if (e1.getBranch().isPresent()) {
+ if (repositories.stream()
+ .anyMatch(e2 -> Objects.equals(
+ e2.getName(), e1.getName()) &&
+ Objects.equals(
+ e2.getDefaultBranch(), e1.getBranch().get()))) {
+ return true;
+ }
- if (element.getBranch().isPresent()) {
- response = gitHubClientService
+ try {
+ return gitHubClientService
.getRepository(
token,
- element.getOwner(),
- element.getName(),
- element.getBranch().get());
- } else {
- response = gitHubClientService
- .getRepository(
- token,
- element.getOwner(),
- element.getName());
- }
+ e1.getOwner(),
+ e1.getName(),
+ e1.getBranch().get())
+ .getStatus() == HttpStatus.SC_OK;
+ } catch (WebApplicationException e) {
+ System.out.println(e.getMessage());
- if (response.getStatus() != HttpStatus.SC_OK) {
return false;
}
- } catch (WebApplicationException e) {
- return false;
}
- return true;
+ return repositories.stream()
+ .anyMatch(e2 -> Objects.equals(e2.getName(), e1.getName()));
});
}
}
diff --git a/api-server/src/main/java/com/repoachiever/service/workspace/WorkspaceService.java b/api-server/src/main/java/com/repoachiever/service/workspace/WorkspaceService.java
index 8218ff7..057c1ad 100644
--- a/api-server/src/main/java/com/repoachiever/service/workspace/WorkspaceService.java
+++ b/api-server/src/main/java/com/repoachiever/service/workspace/WorkspaceService.java
@@ -392,7 +392,7 @@ public void removeEarliestRawContentFile(String workspaceUnitDirectory, String l
*
* @param workspaceUnitDirectory given workspace unit directory.
* @param location given location of the additional content file.
- * @param name given name of the additional content file.
+ * @param name given name of the raws content file.
* @return result if additional content file exists in the given workspace unit directory.
*/
public Boolean isRawContentFileExist(String workspaceUnitDirectory, String location, String name) {
diff --git a/api-server/src/main/resources/application.properties b/api-server/src/main/resources/application.properties
index e304b0a..83e60ff 100644
--- a/api-server/src/main/resources/application.properties
+++ b/api-server/src/main/resources/application.properties
@@ -22,6 +22,15 @@ quarkus.rest-client.github.url=https://api.github.com
# Describes timeout used by GitHub client.
quarkus.rest-client.github.connect-timeout=10000
+# Describes page size used by GitHub client.
+rest-client.github.page-size=100
+
+# Describes max page used by GitHub client.
+rest-client.github.max-page=1000
+
+# Describes visibility of repositories to be retreived by GitHub client.
+rest-client.github.repo-visibility=all
+
# Describes internal healthcheck client configuration.
quarkus.rest-client.small-rye-health-check.url=http://${quarkus.http.host}:${quarkus.http.port}
diff --git a/cluster/src/main/java/com/repoachiever/entity/ConfigEntity.java b/cluster/src/main/java/com/repoachiever/entity/ConfigEntity.java
index 6f1cd6a..96f748e 100644
--- a/cluster/src/main/java/com/repoachiever/entity/ConfigEntity.java
+++ b/cluster/src/main/java/com/repoachiever/entity/ConfigEntity.java
@@ -171,11 +171,6 @@ public static class Resource {
@Getter
public static class Worker {
@NotNull
- @Pattern(
- regexp =
- "(((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?)|(([\\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9]))|([\\?])|([\\*]))[\\s](((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?)|(([\\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9]))|([\\?])|([\\*]))[\\s](((([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?,)*([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?)|(([\\*]|[0-9]|[0-1][0-9]|[2][0-3])/([0-9]|[0-1][0-9]|[2][0-3]))|([\\?])|([\\*]))[\\s](((([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?,)*([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?(C)?)|(([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])/([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(C)?)|(L(-[0-9])?)|(L(-[1-2][0-9])?)|(L(-[3][0-1])?)|(LW)|([1-9]W)|([1-3][0-9]W)|([\\?])|([\\*]))[\\s](((([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?,)*([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?)|(([1-9]|0[1-9]|1[0-2])/([1-9]|0[1-9]|1[0-2]))|(((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?,)*(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?)|((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)/(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))|([\\?])|([\\*]))[\\s]((([1-7](-([1-7]))?,)*([1-7])(-([1-7]))?)|([1-7]/([1-7]))|(((MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?,)*(MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?(C)?)|((MON|TUE|WED|THU|FRI|SAT|SUN)/(MON|TUE|WED|THU|FRI|SAT|SUN)(C)?)|(([1-7]|(MON|TUE|WED|THU|FRI|SAT|SUN))?(L|LW)?)|(([1-7]|MON|TUE|WED|THU|FRI|SAT|SUN)#([1-7])?)|([\\?])|([\\*]))([\\s]?(([\\*])?|(19[7-9][0-9])|(20[0-9][0-9]))?|"
- + " (((19[7-9][0-9])|(20[0-9][0-9]))/((19[7-9][0-9])|(20[0-9][0-9])))?|"
- + " ((((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?,)*((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?)?)")
@JsonProperty("frequency")
public String frequency;
}
diff --git a/cluster/src/main/java/com/repoachiever/exception/ConfigCronExpressionValidationException.java b/cluster/src/main/java/com/repoachiever/exception/ConfigCronExpressionValidationException.java
new file mode 100644
index 0000000..87d8f8c
--- /dev/null
+++ b/cluster/src/main/java/com/repoachiever/exception/ConfigCronExpressionValidationException.java
@@ -0,0 +1,22 @@
+package com.repoachiever.exception;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Formatter;
+
+/**
+ * Represents exception used when configuration file cron expression validation
+ * process fails.
+ */
+public class ConfigCronExpressionValidationException extends IOException {
+ public ConfigCronExpressionValidationException() {
+ this("");
+ }
+
+ public ConfigCronExpressionValidationException(Object... message) {
+ super(
+ new Formatter()
+ .format("Config file cron expression is not valid: %s", Arrays.stream(message).toArray())
+ .toString());
+ }
+}
diff --git a/cluster/src/main/java/com/repoachiever/service/config/ConfigService.java b/cluster/src/main/java/com/repoachiever/service/config/ConfigService.java
index 66066fa..55241d2 100644
--- a/cluster/src/main/java/com/repoachiever/service/config/ConfigService.java
+++ b/cluster/src/main/java/com/repoachiever/service/config/ConfigService.java
@@ -12,6 +12,7 @@
import com.repoachiever.exception.ConfigFileReadingFailureException;
import com.repoachiever.exception.ConfigNotGivenException;
import com.repoachiever.exception.ConfigValidationException;
+import com.repoachiever.exception.ConfigCronExpressionValidationException;
import jakarta.annotation.PostConstruct;
import java.io.IOException;
@@ -28,6 +29,7 @@
import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.util.CronExpression;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -95,6 +97,12 @@ private void configure() throws
.collect(Collectors.joining(", ")));
}
}
+
+ if (!CronExpression.isValidExpression(
+ config.getResource().getWorker().getFrequency())) {
+ throw new ConfigValidationException(
+ new ConfigCronExpressionValidationException().getMessage());
+ }
} finally {
try {
configFile.close();
diff --git a/cluster/src/main/java/com/repoachiever/service/integration/scheduler/SchedulerConfigService.java b/cluster/src/main/java/com/repoachiever/service/integration/scheduler/SchedulerConfigService.java
index 42e95da..82b7ecd 100644
--- a/cluster/src/main/java/com/repoachiever/service/integration/scheduler/SchedulerConfigService.java
+++ b/cluster/src/main/java/com/repoachiever/service/integration/scheduler/SchedulerConfigService.java
@@ -37,15 +37,16 @@ public class SchedulerConfigService {
/**
* Performs configuration of RepoAchiever Cluster workers.
*
- * @throws SchedulerPeriodRetrievalFailureException if scheduler period retrieval process failed.
+ * @throws SchedulerPeriodRetrievalFailureException if scheduler period
+ * retrieval process failed.
*/
@PostConstruct
private void process() throws SchedulerPeriodRetrievalFailureException {
- ExecutorService starterExecutorService =
- Executors.newFixedThreadPool(configService.getConfig().getContent().getLocations().size());
+ ExecutorService starterExecutorService = Executors
+ .newFixedThreadPool(configService.getConfig().getContent().getLocations().size());
- ScheduledExecutorService operationScheduledExecutorService =
- Executors.newScheduledThreadPool(configService.getConfig().getContent().getLocations().size());
+ ScheduledExecutorService operationScheduledExecutorService = Executors
+ .newScheduledThreadPool(configService.getConfig().getContent().getLocations().size());
Long period;
@@ -74,8 +75,7 @@ private void process() throws SchedulerPeriodRetrievalFailureException {
logger.info(
LoggingConfigurationHelper.getTransferableMessage(
String.format("Skipping execution for '%s' location due to suspension",
- element.getName())
- ));
+ element.getName())));
return;
}
@@ -87,17 +87,14 @@ private void process() throws SchedulerPeriodRetrievalFailureException {
StateService.resetSuspenderByName(element.getName());
- CountDownLatch awaiter = StateService.getSuspenderAwaiterByName(element.getName());
-
if (!vendorFacade.isVendorAvailable()) {
logger.info(
LoggingConfigurationHelper.getTransferableMessage(
String.format("Remote provider '%s' is not available: '%s'",
configService.getConfig().getService().getProvider().toString(),
- element.getName())
- ));
+ element.getName())));
- awaiter.countDown();
+ StateService.countDownSuspenderByName(element.getName());
return;
}
@@ -116,8 +113,6 @@ record = vendorFacade.getLatestRecord(element.getName());
element.getName(),
e.getMessage())));
- StateService.removeSuspenderByName(element.getName());
-
closable.countDown();
return;
@@ -129,7 +124,7 @@ record = vendorFacade.getLatestRecord(element.getName());
element.getName(),
e.getMessage())));
- awaiter.countDown();
+ StateService.countDownSuspenderByName(element.getName());
return;
}
@@ -137,13 +132,19 @@ record = vendorFacade.getLatestRecord(element.getName());
Boolean rawContentPresent = false;
try {
- rawContentPresent =
- apiServerCommunicationResource.retrieveRawContentPresent(
- element.getName(), record);
+ rawContentPresent = apiServerCommunicationResource.retrieveRawContentPresent(
+ element.getName(), record);
} catch (ApiServerOperationFailureException ignored) {
}
if (!rawContentPresent) {
+ logger.info(
+ LoggingConfigurationHelper.getTransferableMessage(
+ String.format(
+ "Raw content record '%s' for '%s' location is not present",
+ record,
+ element.getName())));
+
logger.info(
LoggingConfigurationHelper.getTransferableMessage(
String.format(
@@ -191,8 +192,6 @@ record = vendorFacade.getLatestRecord(element.getName());
}
}
- StateService.removeSuspenderByName(element.getName());
-
closable.countDown();
return;
@@ -217,7 +216,7 @@ record = vendorFacade.getLatestRecord(element.getName());
}
}
- awaiter.countDown();
+ StateService.countDownSuspenderByName(element.getName());
return;
}
@@ -253,7 +252,7 @@ record = vendorFacade.getLatestRecord(element.getName());
element.getName(),
e.getMessage())));
- awaiter.countDown();
+ StateService.countDownSuspenderByName(element.getName());
return;
}
@@ -264,6 +263,13 @@ record = vendorFacade.getLatestRecord(element.getName());
"Raw content transfer finished for '%s' location and '%s' record",
element.getName(),
record)));
+ } else {
+ logger.info(
+ LoggingConfigurationHelper.getTransferableMessage(
+ String.format(
+ "Raw content record '%s' for '%s' location is already present",
+ record,
+ element.getName())));
}
AdditionalContentDto additionalContent;
@@ -278,8 +284,6 @@ record = vendorFacade.getLatestRecord(element.getName());
element.getName(),
e.getMessage())));
- StateService.removeSuspenderByName(element.getName());
-
closable.countDown();
return;
@@ -291,7 +295,7 @@ record = vendorFacade.getLatestRecord(element.getName());
element.getName(),
e.getMessage())));
- awaiter.countDown();
+ StateService.countDownSuspenderByName(element.getName());
return;
}
@@ -300,13 +304,19 @@ record = vendorFacade.getLatestRecord(element.getName());
Boolean additionalContentPresent = false;
try {
- additionalContentPresent =
- apiServerCommunicationResource.retrieveAdditionalContentPresent(
+ additionalContentPresent = apiServerCommunicationResource
+ .retrieveAdditionalContentPresent(
element.getName(), additionalContent.getHash());
} catch (ApiServerOperationFailureException ignored) {
}
if (!additionalContentPresent) {
+ logger.info(
+ LoggingConfigurationHelper.getTransferableMessage(
+ String.format(
+ "Additional content for '%s' location is not present",
+ element.getName())));
+
logger.info(
LoggingConfigurationHelper.getTransferableMessage(
String.format(
@@ -316,7 +326,8 @@ record = vendorFacade.getLatestRecord(element.getName());
try {
apiServerCommunicationResource.performAdditionalContentUpload(
- element.getName(), additionalContent.getHash(), additionalContent.getData());
+ element.getName(), additionalContent.getHash(),
+ additionalContent.getData());
} catch (ApiServerOperationFailureException e) {
logger.info(
LoggingConfigurationHelper.getTransferableMessage(
@@ -325,7 +336,7 @@ record = vendorFacade.getLatestRecord(element.getName());
element.getName(),
e.getMessage())));
- awaiter.countDown();
+ StateService.countDownSuspenderByName(element.getName());
return;
}
@@ -336,11 +347,23 @@ record = vendorFacade.getLatestRecord(element.getName());
"Additional content transfer finished for '%s' location and '%s' hash",
element.getName(),
additionalContent.getHash())));
+ } else {
+ logger.info(
+ LoggingConfigurationHelper.getTransferableMessage(
+ String.format(
+ "Additional content for '%s' location is already present",
+ element.getName())));
}
}
+ } catch (Exception e) {
+ StateService.countDownSuspenderByName(element.getName());
- awaiter.countDown();
+ logger.info(
+ LoggingConfigurationHelper.getTransferableMessage(
+ String.format("ERROR APPERAED '%s' location", element.getName())));
} finally {
+ StateService.countDownSuspenderByName(element.getName());
+
logger.info(
LoggingConfigurationHelper.getTransferableMessage(
String.format("Exiting execution for '%s' location", element.getName())));
@@ -353,7 +376,13 @@ record = vendorFacade.getLatestRecord(element.getName());
logger.fatal(e.getMessage());
}
+ StateService.removeSuspenderByName(element.getName());
+
execution.cancel(true);
+
+ logger.info(
+ LoggingConfigurationHelper.getTransferableMessage(
+ String.format("Operations were cancelled for '%s' location", element.getName())));
});
});
}
diff --git a/cluster/src/main/java/com/repoachiever/service/state/StateService.java b/cluster/src/main/java/com/repoachiever/service/state/StateService.java
index 536d1fb..11ff249 100644
--- a/cluster/src/main/java/com/repoachiever/service/state/StateService.java
+++ b/cluster/src/main/java/com/repoachiever/service/state/StateService.java
@@ -76,59 +76,28 @@ public static void resetSuspenderByName(String name) {
}
/**
- * Retrieves RepoAchiever Cluster suspender awaiter by the given name.
+ * Counts down RepoAchiever Cluster suspender suspender by the given name.
*
* @param name given RepoAchiever Cluster suspender name.
- * @return retrieved RepoAchiever Cluster suspender awaiter name.
*/
- public static CountDownLatch getSuspenderAwaiterByName(String name) {
- return suspenders
+ public static void countDownSuspenderByName(String name) {
+ suspenders
.stream()
.filter(element -> Objects.equals(element.getName(), name))
.toList()
.getFirst()
.getAwaiter()
- .get();
+ .get()
+ .countDown();
}
+
/**
* Represents RepoAchiever Cluster suspend state guard.
*/
@Getter
private final static ReentrantLock suspendGuard = new ReentrantLock();
-// /**
-// * Represents a set of content updates head counter, pointing at the latest scanned head of the stream for the
-// * provided content locations. As keys there are used provided location names and as values commit amounts are used.
-// */
-// private final static Map contentUpdatesHeadCounterSet = new HashMap<>();
-//
-// /**
-// * Adds current content update head counter for the given location name with the given value.
-// *
-// * @param location given content location.
-// * @param value given content value.
-// */
-// public static void setContentUpdatesHeadCounter(String location, Integer value) {
-// contentUpdatesHeadCounterSet.put(location, value);
-// }
-
-// /**
-// * Checks if current content update head counter for the given location name is below or equal to the given value.
-// *
-// * @return result of the check.
-// */
-// public static Boolean isContentUpdateHeadCounterBelow(String location, Integer value) {
-// return contentUpdatesHeadCounterSet.getOrDefault(location, 0) < value;
-// }
-
-// /**
-// * Resets current content update head counter.
-// */
-// public static void resetContentUpdatesHeadCounter() {
-// contentUpdatesHeadCounterSet.clear();
-// }
-
/**
* Represents log message queue used to handle RepoAchiever API Server log message transfer.
*/
diff --git a/cluster/src/main/java/com/repoachiever/service/vendor/common/VendorConfigurationHelper.java b/cluster/src/main/java/com/repoachiever/service/vendor/common/VendorConfigurationHelper.java
index dfbcd27..cf847ae 100644
--- a/cluster/src/main/java/com/repoachiever/service/vendor/common/VendorConfigurationHelper.java
+++ b/cluster/src/main/java/com/repoachiever/service/vendor/common/VendorConfigurationHelper.java
@@ -15,6 +15,7 @@
import java.io.IOException;
import java.net.InetAddress;
import java.security.MessageDigest;
+import java.util.Objects;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -54,7 +55,9 @@ public GitHubLocationNotationDto parseLocationGitHubNotation(String location)
throw new LocationDefinitionsAreNotValidException();
}
- if (matcher.groupCount() == 4) {
+ String optionalMatch = matcher.group(4);
+
+ if (matcher.groupCount() == 4 && Objects.nonNull(optionalMatch)) {
return GitHubLocationNotationDto.of(
matcher.group(1),
matcher.group(2),
diff --git a/cluster/src/main/java/com/repoachiever/service/vendor/git/github/GitGitHubVendorService.java b/cluster/src/main/java/com/repoachiever/service/vendor/git/github/GitGitHubVendorService.java
index 04fea2f..52e70de 100644
--- a/cluster/src/main/java/com/repoachiever/service/vendor/git/github/GitGitHubVendorService.java
+++ b/cluster/src/main/java/com/repoachiever/service/vendor/git/github/GitGitHubVendorService.java
@@ -9,11 +9,14 @@
import com.repoachiever.exception.GitHubContentRetrievalFailureException;
import com.repoachiever.exception.GitHubGraphQlClientDocumentNotFoundException;
import com.repoachiever.exception.GitHubServiceNotAvailableException;
+import com.repoachiever.logging.common.LoggingConfigurationHelper;
import com.repoachiever.service.config.ConfigService;
+import com.repoachiever.service.integration.scheduler.SchedulerConfigService;
import com.repoachiever.service.state.StateService;
import com.repoachiever.service.vendor.common.VendorConfigurationHelper;
import jakarta.annotation.PostConstruct;
import jakarta.ws.rs.core.HttpHeaders;
+
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
@@ -270,6 +273,7 @@ public DataBuffer getCommitContent(String owner, String name, String format, Str
.build())
.retrieve()
.bodyToMono(DataBuffer.class)
+ .onErrorResume(element -> Mono.empty())
.block();
dataBufferAtomic.set(response);
diff --git a/gui/src/main/java/com/repoachiever/service/element/list/ListVisualizer.java b/gui/src/main/java/com/repoachiever/service/element/list/ListVisualizer.java
index e9ac179..3d65f2f 100644
--- a/gui/src/main/java/com/repoachiever/service/element/list/ListVisualizer.java
+++ b/gui/src/main/java/com/repoachiever/service/element/list/ListVisualizer.java
@@ -30,116 +30,125 @@
*/
@Service
public class ListVisualizer
- implements IElementResizable, IElementActualizable, IElement> {
- private final UUID id = UUID.randomUUID();
-
- @Lazy
- @Autowired
- private MainDeploymentScene deploymentScene;
-
- public ListVisualizer(
- @Autowired PropertiesEntity properties,
- @Autowired ApplicationEventPublisher applicationEventPublisher,
- @Lazy @Autowired MainDeploymentScene deploymentScene) {
- ListView listView = new ListView<>();
-
- listView.setCellFactory(element ->
- new ListVisualizerCell(properties, applicationEventPublisher, deploymentScene));
-
- listView.setOnMouseClicked(
- event -> {
- if (Objects.nonNull(listView.getSelectionModel().getSelectedItem())) {
- ContentRetrievalResult content = StateService.getContent();
-
- applicationEventPublisher.publishEvent(
- new ContentSwapEvent(
- content
- .getLocations()
- .stream()
- .filter(
- element ->
- element
- .getName()
- .equals(
- listView
- .getSelectionModel()
- .getSelectedItem()
- .getName()))
- .toList()
- .getFirst()));
- }
- });
-
- ElementStorage.setElement(id, listView);
- ElementStorage.setActualizable(this);
- ElementStorage.setResizable(this);
- }
-
- /**
- * @see IElement
- */
- @Override
- public ListView getContent() {
- return ElementStorage.getElement(id);
- }
-
- /**
- * @see IElementResizable
- */
- @Override
- public void handlePrefWidth() {
- getContent().setMaxWidth(StateService.getMainWindowWidth());
- }
-
- /**
- * @see IElementResizable
- */
- @Override
- public void handlePrefHeight() {
- getContent().setMaxHeight(StateService.getMainWindowHeight());
- }
-
- /**
- * @see IElementActualizable
- */
- @Override
- public void handleBackgroundUpdates() {
- ContentRetrievalResult content = StateService.getContent();
-
- Platform.runLater(
- () -> {
- ObservableList observableList;
-
- if (!Objects.isNull(content)) {
- List items =
- content
- .getLocations()
- .stream()
- .sorted(Comparator.comparing(ContentRetrievalUnit::getName))
- .map(element ->
- ListVisualizerCellInputDto.of(
- element.getName(),
- element.getActive(),
- element.getAdditional().getVersions().isEmpty()
- && element.getRaw().getVersions().isEmpty()))
- .toList();
-
- observableList =
- FXCollections.observableList(items);
-
- getContent().setMouseTransparent(false);
- getContent().setFocusTraversable(true);
- } else {
- List items = Stream.of(ListVisualizerCellInputDto.stub()).toList();
-
- observableList =
- FXCollections.observableList(items);
-
- getContent().setMouseTransparent(true);
- getContent().setFocusTraversable(false);
- }
-
- getContent().setItems(observableList);
- });
- }
+ implements IElementResizable, IElementActualizable, IElement> {
+ private final UUID id = UUID.randomUUID();
+
+ private PropertiesEntity properties;
+
+ private ApplicationEventPublisher applicationEventPublisher;
+
+ private MainDeploymentScene deploymentScene;
+
+ public ListVisualizer(
+ @Autowired PropertiesEntity properties,
+ @Autowired ApplicationEventPublisher applicationEventPublisher,
+ @Lazy @Autowired MainDeploymentScene deploymentScene) {
+ ListView listView = new ListView<>();
+
+ listView.setCellFactory(element -> new ListVisualizerCell(properties, applicationEventPublisher,
+ deploymentScene));
+
+ listView.setOnMouseClicked(
+ event -> {
+ if (Objects.nonNull(listView.getSelectionModel().getSelectedItem())) {
+ ContentRetrievalResult content = StateService.getContent();
+
+ applicationEventPublisher.publishEvent(
+ new ContentSwapEvent(
+ content
+ .getLocations()
+ .stream()
+ .filter(
+ element -> element
+ .getName()
+ .equals(
+ listView
+ .getSelectionModel()
+ .getSelectedItem()
+ .getName()))
+ .toList()
+ .getFirst()));
+ }
+ });
+
+ this.properties = properties;
+ this.applicationEventPublisher = applicationEventPublisher;
+ this.deploymentScene = deploymentScene;
+
+ ElementStorage.setElement(id, listView);
+ ElementStorage.setActualizable(this);
+ ElementStorage.setResizable(this);
+ }
+
+ /**
+ * @see IElement
+ */
+ @Override
+ public ListView getContent() {
+ return ElementStorage.getElement(id);
+ }
+
+ /**
+ * @see IElementResizable
+ */
+ @Override
+ public void handlePrefWidth() {
+ getContent().setMaxWidth(StateService.getMainWindowWidth());
+ }
+
+ /**
+ * @see IElementResizable
+ */
+ @Override
+ public void handlePrefHeight() {
+ getContent().setMaxHeight(StateService.getMainWindowHeight());
+ }
+
+ /**
+ * @see IElementActualizable
+ */
+ @Override
+ public void handleBackgroundUpdates() {
+ ContentRetrievalResult content = StateService.getContent();
+
+ Platform.runLater(
+ () -> {
+ ObservableList observableList;
+
+ if (!Objects.isNull(content)) {
+ List items = content
+ .getLocations()
+ .stream()
+ .sorted(Comparator.comparing(
+ ContentRetrievalUnit::getName))
+ .map(element -> ListVisualizerCellInputDto.of(
+ element.getName(),
+ element.getActive(),
+ element.getAdditional().getVersions()
+ .isEmpty()
+ && element.getRaw()
+ .getVersions()
+ .isEmpty()))
+ .toList();
+
+ observableList = FXCollections.observableList(items);
+
+ getContent().setMouseTransparent(false);
+ getContent().setFocusTraversable(true);
+ } else {
+ List items = Stream
+ .of(ListVisualizerCellInputDto.stub()).toList();
+
+ observableList = FXCollections.observableList(items);
+
+ getContent().setMouseTransparent(true);
+ getContent().setFocusTraversable(false);
+ }
+
+ getContent().setCellFactory(element -> new ListVisualizerCell(properties,
+ applicationEventPublisher, deploymentScene));
+
+ getContent().setItems(observableList);
+ });
+ }
}
diff --git a/pom.xml b/pom.xml
index 1067c09..3668539 100644
--- a/pom.xml
+++ b/pom.xml
@@ -243,6 +243,11 @@
jboss-logging
3.4.3.Final
+
+ org.jboss.logmanager
+ log4j2-jboss-logmanager
+ 2.0.1.Final
+
jakarta.json
jakarta.json-api
diff --git a/samples/config/api-server/api-server.yaml b/samples/config/api-server/api-server.yaml
index 9d69084..17540ab 100644
--- a/samples/config/api-server/api-server.yaml
+++ b/samples/config/api-server/api-server.yaml
@@ -51,4 +51,4 @@ resource:
# Represents a set of options used for RepoAchiever Cluster worker configuration.
worker:
# Represents frequency of requests to selected VCS provider resources.
- frequency: "0/30 * * * * ?"
\ No newline at end of file
+ frequency: "0 */5 * * * ?"
\ No newline at end of file