diff --git a/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponse.java b/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponse.java index 26084ad077..513aff6891 100644 --- a/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponse.java +++ b/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponse.java @@ -33,13 +33,13 @@ public class ThingsboardErrorResponse { // Error code private final ThingsboardErrorCode errorCode; - private final Date timestamp; + private final long timestamp; protected ThingsboardErrorResponse(final String message, final ThingsboardErrorCode errorCode, HttpStatus status) { this.message = message; this.errorCode = errorCode; this.status = status; - this.timestamp = new java.util.Date(); + this.timestamp = System.currentTimeMillis(); } public static ThingsboardErrorResponse of(final String message, final ThingsboardErrorCode errorCode, HttpStatus status) { @@ -75,7 +75,7 @@ public class ThingsboardErrorResponse { } @ApiModelProperty(position = 4, value = "Timestamp", accessMode = ApiModelProperty.AccessMode.READ_ONLY) - public Date getTimestamp() { + public long getTimestamp() { return timestamp; } } diff --git a/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java b/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java index b2509187d5..2e572ce8c4 100644 --- a/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java +++ b/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java @@ -16,6 +16,8 @@ package org.thingsboard.server.exception; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.boot.web.servlet.error.ErrorController; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -28,7 +30,9 @@ import org.springframework.security.authentication.LockedException; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.context.request.WebRequest; @@ -43,16 +47,21 @@ import org.thingsboard.server.service.security.exception.JwtExpiredTokenExceptio import org.thingsboard.server.service.security.exception.UserPasswordExpiredException; import org.thingsboard.server.service.security.exception.UserPasswordNotValidException; +import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.HashMap; import java.util.Map; +import java.util.Optional; + +import static javax.servlet.RequestDispatcher.ERROR_EXCEPTION; @Slf4j +@Controller @RestControllerAdvice -public class ThingsboardErrorResponseHandler extends ResponseEntityExceptionHandler implements AccessDeniedHandler { +public class ThingsboardErrorResponseHandler extends ResponseEntityExceptionHandler implements AccessDeniedHandler, ErrorController { private static final Map statusToErrorCodeMap = new HashMap<>(); static { @@ -90,6 +99,17 @@ public class ThingsboardErrorResponseHandler extends ResponseEntityExceptionHand return errorCodeToStatusMap.getOrDefault(errorCode, HttpStatus.INTERNAL_SERVER_ERROR); } + @RequestMapping("/error") + public ResponseEntity handleError(HttpServletRequest request) { + HttpStatus httpStatus = Optional.ofNullable(request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)) + .map(status -> HttpStatus.resolve(Integer.parseInt(status.toString()))) + .orElse(HttpStatus.INTERNAL_SERVER_ERROR); + String errorMessage = Optional.ofNullable(request.getAttribute(ERROR_EXCEPTION)) + .map(e -> (ExceptionUtils.getMessage((Throwable) e))) + .orElse(httpStatus.getReasonPhrase()); + return new ResponseEntity<>(ThingsboardErrorResponse.of(errorMessage, statusToErrorCode(httpStatus), httpStatus), httpStatus); + } + @Override @ExceptionHandler(AccessDeniedException.class) public void handle(HttpServletRequest request, HttpServletResponse response, diff --git a/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitRepositoryService.java b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitRepositoryService.java index 24d23c60a1..6b6812b8ef 100644 --- a/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitRepositoryService.java +++ b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitRepositoryService.java @@ -157,12 +157,10 @@ public class DefaultGitRepositoryService implements GitRepositoryService { @Override public void fetch(TenantId tenantId) throws GitAPIException { - var repository = repositories.get(tenantId); - if (repository != null) { - log.debug("[{}] Fetching tenant repository.", tenantId); - repository.fetch(); - log.debug("[{}] Fetched tenant repository.", tenantId); - } + var repository = checkRepository(tenantId); + log.debug("[{}] Fetching tenant repository.", tenantId); + repository.fetch(); + log.debug("[{}] Fetched tenant repository.", tenantId); } @Override @@ -195,8 +193,17 @@ public class DefaultGitRepositoryService implements GitRepositoryService { } private GitRepository checkRepository(TenantId tenantId) { - return Optional.ofNullable(repositories.get(tenantId)) + GitRepository gitRepository = Optional.ofNullable(repositories.get(tenantId)) .orElseThrow(() -> new IllegalStateException("Repository is not initialized")); + + if (!Files.exists(Path.of(gitRepository.getDirectory()))) { + try { + return cloneRepository(tenantId, gitRepository.getSettings()); + } catch (Exception e) { + throw new IllegalStateException("Could not initialize the repository: " + e.getMessage(), e); + } + } + return gitRepository; } @Override @@ -229,17 +236,7 @@ public class DefaultGitRepositoryService implements GitRepositoryService { testRepository(tenantId, settings); clearRepository(tenantId); - log.debug("[{}] Init tenant repository started.", tenantId); - Path repositoryDirectory = Path.of(repositoriesFolder, tenantId.getId().toString()); - GitRepository repository; - if (Files.exists(repositoryDirectory)) { - FileUtils.forceDelete(repositoryDirectory.toFile()); - } - - Files.createDirectories(repositoryDirectory); - repository = GitRepository.clone(settings, repositoryDirectory.toFile()); - repositories.put(tenantId, repository); - log.debug("[{}] Init tenant repository completed.", tenantId); + cloneRepository(tenantId, settings); } @Override @@ -276,4 +273,18 @@ public class DefaultGitRepositoryService implements GitRepositoryService { String entityId = StringUtils.substringBetween(path, "/", ".json"); return EntityIdFactory.getByTypeAndUuid(entityType, entityId); } + + private GitRepository cloneRepository(TenantId tenantId, RepositorySettings settings) throws Exception { + log.debug("[{}] Init tenant repository started.", tenantId); + Path repositoryDirectory = Path.of(repositoriesFolder, tenantId.getId().toString()); + + if (Files.exists(repositoryDirectory)) { + FileUtils.forceDelete(repositoryDirectory.toFile()); + } + Files.createDirectories(repositoryDirectory); + GitRepository repository = GitRepository.clone(settings, repositoryDirectory.toFile()); + repositories.put(tenantId, repository); + log.debug("[{}] Init tenant repository completed.", tenantId); + return repository; + } }