package edu.ml.tensorflow.service.storage.impl; import edu.ml.tensorflow.ApplicationProperties; import edu.ml.tensorflow.service.storage.StorageService; import edu.ml.tensorflow.service.storage.exception.StorageException; import edu.ml.tensorflow.service.storage.exception.StorageFileNotFoundException; import groovy.lang.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.Resource; import org.springframework.core.io.UrlResource; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.util.FileSystemUtils; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.net.MalformedURLException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.time.LocalDateTime; import java.util.UUID; import java.util.stream.Stream; @Service @Singleton @EnableScheduling public class FileSystemStorageService implements StorageService { private final static Logger LOGGER = LoggerFactory.getLogger(FileSystemStorageService.class); private final Path uploadLocation; private final Path predictedLocation; @Autowired public FileSystemStorageService(final ApplicationProperties applicationProperties) { this.uploadLocation = Paths.get(applicationProperties.getUploadDir()); this.predictedLocation = Paths.get(applicationProperties.getOutputDir()); cleanUpFolders(); } @Override public String store(MultipartFile file) { String filename = StringUtils.cleanPath(file.getOriginalFilename()); try { if (file.isEmpty()) { throw new StorageException("Failed to store empty file " + filename); } if (filename.contains("..")) { // This is a security check throw new StorageException("Cannot store file with relative path outside current directory " + filename); } String newFileName = UUID.randomUUID() + ".jpg"; Files.copy(file.getInputStream(), this.uploadLocation.resolve(newFileName), StandardCopyOption.REPLACE_EXISTING); return newFileName; } catch (IOException e) { throw new StorageException("Failed to store file " + filename, e); } } @Override public Stream<Path> loadAll() { try { return Files.walk(this.uploadLocation, 1) .filter(path -> !path.equals(this.uploadLocation)) .map(path -> this.uploadLocation.relativize(path)); } catch (IOException e) { throw new StorageException("Failed to read stored files", e); } } @Override public Path load(String filename) { return uploadLocation.resolve(filename); } @Override public Resource loadAsResource(String filename) { try { Path file = load(filename); Resource resource = new UrlResource(file.toUri()); if (resource.exists() || resource.isReadable()) { return resource; } else { throw new StorageFileNotFoundException( "Could not read file: " + filename); } } catch (MalformedURLException e) { throw new StorageFileNotFoundException("Could not read file: " + filename, e); } } @Override public void deleteAll() { FileSystemUtils.deleteRecursively(uploadLocation.toFile()); FileSystemUtils.deleteRecursively(predictedLocation.toFile()); LOGGER.info("Target folders cleaned up at: {}", LocalDateTime.now()); } @Override public void init() { try { Files.createDirectories(uploadLocation); Files.createDirectories(predictedLocation); LOGGER.info("Target folders initialized at: {}", LocalDateTime.now()); } catch (IOException e) { throw new StorageException("Could not initialize storage", e); } } @Scheduled(fixedRate = 1000 * 3600) private void cleanUpFolders() { deleteAll(); init(); } }