1 package hu.user.mediacube.integration.safedelete;
3 import hu.user.mediacube.integration.safedelete.services.ArchiveStatusService;
4 import hu.user.mediacube.integration.safedelete.services.StatusFileService;
5 import hu.user.mediacube.integration.safedelete.verifier.MediaCubeDatabaseService;
6 import hu.user.mediacube.integration.safedelete.verifier.TSMService;
7 import lombok.extern.log4j.Log4j2;
8 import org.springframework.beans.factory.annotation.Autowired;
9 import org.springframework.stereotype.Component;
11 import java.io.IOException;
12 import java.nio.file.DirectoryStream;
13 import java.nio.file.Files;
14 import java.nio.file.Path;
15 import java.nio.file.Paths;
16 import java.time.Duration;
17 import java.time.Instant;
18 import java.time.LocalDate;
19 import java.time.format.DateTimeFormatter;
21 import java.util.TimeZone;
25 public class SafeDeleteCommand {
27 private SafeDeleteProperties safeDeleteProperties;
30 private MediaCubeDatabaseService mediaCubeDatabaseService;
33 private TSMService tsmService;
36 private ArchiveStatusService archivestatusService;
39 private StatusFileService statusFileService;
41 private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").withZone(TimeZone.getDefault().toZoneId());
43 public void processDirectory(String directory, boolean forceDeleteArchived) throws IOException {
44 archivestatusService.logHeader();
45 final Instant start = Instant.now();
46 log.info("Check directory: {}", directory);
47 log.info("Delete already archived: {}", forceDeleteArchived);
48 Path inputPath = Paths.get(directory);
50 Set<String> fileNamesWithKillDates = statusFileService.loadFileNamesWithKillDates(inputPath);
52 try (DirectoryStream<Path> stream = Files.newDirectoryStream(inputPath, FileOperations.filterOnlyFiles())) {
53 for (Path filePath : stream) {
54 ArchiveFileStatus status = archivestatusService.createStatus(filePath);
57 process(filePath, status, fileNamesWithKillDates, forceDeleteArchived);
58 } catch (Exception e) {
59 log.error(e.getMessage());
60 FileOperations.silentRename(filePath, FileOperations.ERROR_FILENAME_PREFIX + formatter.format(LocalDate.now()));
62 archivestatusService.logStatus(status);
65 if (safeDeleteProperties.getMaxExecutionHours() > -1
66 && safeDeleteProperties.getMaxExecutionHours() <= Duration.between(start, Instant.now()).toHours()
68 log.info("Reached maximum enabled execution duration {} hours(s)", safeDeleteProperties.getMaxExecutionHours());
75 private void process(Path filePath, ArchiveFileStatus status, Set<String> fileNamesWithKillDates, boolean forceDeleteArchived) throws Exception {
76 boolean canDelete = fileNamesWithKillDates.contains(status.getFileName());
78 if (status.getFileSize() == 0) {
79 processEmptyInputFile(filePath, status, forceDeleteArchived);
81 processInputFile(filePath, status, forceDeleteArchived);
84 log.info("File {} not processed yet by archive system, .killdate status file is missing", filePath.toString());
88 private void processEmptyInputFile(Path source, ArchiveFileStatus status, boolean forceDeleteArchived) throws Exception {
89 status.setMetadataOnly(true);
90 status.setCanDelete(true);
91 if (forceDeleteArchived) {
92 deleteArchivedFileAndStatusFiles(source, status);
96 private void processInputFile(Path source, ArchiveFileStatus status, boolean forceDeleteArchived) throws Exception {
97 log.info("Check MediaCube metadata for {}", source);
98 mediaCubeDatabaseService.verify(source, status);
99 log.info("Check TSM file for {}", source);
100 tsmService.verify(source, status);
101 status.setCanDelete(status.isFileSizeEquals() && status.isHashEquals());
102 if (forceDeleteArchived && status.isCanDelete()) {
103 deleteArchivedFileAndStatusFiles(source, status);
107 private void deleteArchivedFileAndStatusFiles(Path source, ArchiveFileStatus status) throws IOException {
108 String fileName = source.getFileName().toString();
109 Path statusPath = FileOperations.getStatusPath(source);
110 status.setStatusCleanupSuccess(statusFileService.cleanupStatusFiles(statusPath, fileName));
111 status.setDeleteSuccess(FileOperations.silentDelete(source));