add storage
This commit is contained in:
parent
1b92af8762
commit
337556265e
|
@ -49,6 +49,6 @@ bin/
|
|||
.run
|
||||
openDMP/dmp-backend/uploads/
|
||||
openDMP/dmp-backend/tmp/
|
||||
storage/
|
||||
logs/
|
||||
dmp-backend/web/src/main/resources/certificates/
|
||||
/storage/
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package eu.eudat.service.storage;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(StorageFileCleanupProperties.class)
|
||||
public class StorageFileCleanupConfiguration {
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package eu.eudat.service.storage;
|
||||
|
||||
|
||||
import eu.eudat.commons.enums.StorageType;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ConfigurationProperties(prefix = "storage.task")
|
||||
public class StorageFileCleanupProperties {
|
||||
private Boolean enable;
|
||||
private int intervalSeconds;
|
||||
|
||||
public Boolean getEnable() {
|
||||
return enable;
|
||||
}
|
||||
|
||||
public void setEnable(Boolean enable) {
|
||||
this.enable = enable;
|
||||
}
|
||||
|
||||
public int getIntervalSeconds() {
|
||||
return intervalSeconds;
|
||||
}
|
||||
|
||||
public void setIntervalSeconds(int intervalSeconds) {
|
||||
this.intervalSeconds = intervalSeconds;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
package eu.eudat.service.storage;
|
||||
|
||||
import eu.eudat.commons.fake.FakeRequestScope;
|
||||
import eu.eudat.data.StorageFileEntity;
|
||||
import eu.eudat.model.StorageFile;
|
||||
import eu.eudat.query.StorageFileQuery;
|
||||
import gr.cite.tools.data.query.Ordering;
|
||||
import gr.cite.tools.data.query.QueryFactory;
|
||||
import gr.cite.tools.logging.LoggerService;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.EntityManagerFactory;
|
||||
import jakarta.persistence.EntityTransaction;
|
||||
import jakarta.persistence.OptimisticLockException;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Service
|
||||
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
|
||||
public class StorageFileCleanupTask implements Closeable, ApplicationListener<ApplicationReadyEvent> {
|
||||
private class CandidateInfo
|
||||
{
|
||||
private UUID id;
|
||||
private Instant createdAt;
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Instant getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(Instant createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
}
|
||||
|
||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(StorageFileCleanupTask.class));
|
||||
private final StorageFileCleanupProperties _config;
|
||||
private final ApplicationContext applicationContext;
|
||||
private ScheduledExecutorService scheduler;
|
||||
|
||||
public StorageFileCleanupTask(
|
||||
StorageFileCleanupProperties config,
|
||||
ApplicationContext applicationContext) {
|
||||
this._config = config;
|
||||
this.applicationContext = applicationContext;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationReadyEvent event) {
|
||||
long intervalSeconds = this._config .getIntervalSeconds();
|
||||
if (this._config .getEnable() && intervalSeconds > 0) {
|
||||
logger.info("File clean up run in {} seconds", intervalSeconds);
|
||||
|
||||
scheduler = Executors.newScheduledThreadPool(1);
|
||||
scheduler.scheduleAtFixedRate(this::process, 10, intervalSeconds, TimeUnit.SECONDS);
|
||||
} else {
|
||||
scheduler = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (scheduler != null) this.scheduler.close();
|
||||
}
|
||||
|
||||
protected void process() {
|
||||
if (!this._config.getEnable()) return;
|
||||
try {
|
||||
Instant lastCandidateCreationTimestamp = null;
|
||||
while (true) {
|
||||
|
||||
CandidateInfo candidate = this.candidate(lastCandidateCreationTimestamp);
|
||||
if (candidate == null) break;
|
||||
lastCandidateCreationTimestamp = candidate.getCreatedAt();
|
||||
|
||||
logger.debug("Clean up file: {}", candidate.getId());
|
||||
|
||||
boolean successfullyProcessed = this.processStorageFile(candidate.getId());
|
||||
if (!successfullyProcessed) {
|
||||
logger.error("Problem processing file cleanups. {}", candidate.getId());
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.error("Problem processing file cleanups. Breaking for next interval", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean processStorageFile(UUID fileId) {
|
||||
EntityTransaction transaction = null;
|
||||
EntityManager entityManager = null;
|
||||
boolean success = false;
|
||||
try (FakeRequestScope fakeRequestScope = new FakeRequestScope()) {
|
||||
try {
|
||||
QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class);
|
||||
EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class);
|
||||
StorageFileService storageFileService = this.applicationContext.getBean(StorageFileService.class);
|
||||
entityManager = entityManagerFactory.createEntityManager();
|
||||
|
||||
transaction = entityManager.getTransaction();
|
||||
transaction.begin();
|
||||
|
||||
StorageFileEntity item = queryFactory.query(StorageFileQuery.class).ids(fileId).isPurged(false).first();
|
||||
success = true;
|
||||
|
||||
if (item != null) {
|
||||
storageFileService.purgeSafe(fileId);
|
||||
}
|
||||
|
||||
transaction.commit();
|
||||
} catch (OptimisticLockException ex) {
|
||||
// we get this if/when someone else already modified the notifications. We want to essentially ignore this, and keep working
|
||||
logger.debug("Concurrency exception getting file. Skipping: {} ", ex.getMessage());
|
||||
if (transaction != null) transaction.rollback();
|
||||
success = false;
|
||||
} catch (Exception ex) {
|
||||
logger.error("Problem getting list of file. Skipping: {}", ex.getMessage(), ex);
|
||||
if (transaction != null) transaction.rollback();
|
||||
success = false;
|
||||
} finally {
|
||||
if (entityManager != null) entityManager.close();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.error("Problem getting list of file. Skipping: {}", ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private CandidateInfo candidate(Instant lastCandidateCreationTimestamp) {
|
||||
EntityTransaction transaction = null;
|
||||
EntityManager entityManager = null;
|
||||
CandidateInfo candidate = null;
|
||||
try (FakeRequestScope fakeRequestScope = new FakeRequestScope()) {
|
||||
try {
|
||||
QueryFactory queryFactory = this.applicationContext.getBean(QueryFactory.class);
|
||||
EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class);
|
||||
entityManager = entityManagerFactory.createEntityManager();
|
||||
|
||||
transaction = entityManager.getTransaction();
|
||||
transaction.begin();
|
||||
|
||||
StorageFileQuery query = queryFactory.query(StorageFileQuery.class)
|
||||
.canPurge(true)
|
||||
.isPurged(false)
|
||||
.createdAfter(lastCandidateCreationTimestamp);
|
||||
query.setOrder(new Ordering().addAscending(StorageFile._createdAt));
|
||||
StorageFileEntity item = query.first();
|
||||
|
||||
if (item != null) {
|
||||
entityManager.flush();
|
||||
|
||||
candidate = new CandidateInfo();
|
||||
candidate.setId(item.getId());
|
||||
candidate.setCreatedAt(item.getCreatedAt());
|
||||
}
|
||||
|
||||
transaction.commit();
|
||||
} catch (OptimisticLockException ex) {
|
||||
// we get this if/when someone else already modified the notifications. We want to essentially ignore this, and keep working
|
||||
logger.debug("Concurrency exception getting file. Skipping: {} ", ex.getMessage());
|
||||
if (transaction != null) transaction.rollback();
|
||||
candidate = null;
|
||||
} catch (Exception ex) {
|
||||
logger.error("Problem getting list of file. Skipping: {}", ex.getMessage(), ex);
|
||||
if (transaction != null) transaction.rollback();
|
||||
candidate = null;
|
||||
} finally {
|
||||
if (entityManager != null) entityManager.close();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.error("Problem getting list of file. Skipping: {}", ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package eu.eudat.service.storage;
|
||||
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(StorageFileProperties.class)
|
||||
public class StorageFileConfiguration {
|
||||
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package eu.eudat.service.storage;
|
||||
|
||||
|
||||
import eu.eudat.commons.enums.StorageType;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ConfigurationProperties(prefix = "storage.service")
|
||||
public class StorageFileProperties {
|
||||
private List<StorageConfig> storages;
|
||||
private List<StaticFilesConfig> staticFiles;
|
||||
|
||||
private int tempStoreLifetimeSeconds;
|
||||
|
||||
public List<StorageConfig> getStorages() {
|
||||
return storages;
|
||||
}
|
||||
|
||||
public void setStorages(List<StorageConfig> storages) {
|
||||
this.storages = storages;
|
||||
}
|
||||
|
||||
public int getTempStoreLifetimeSeconds() {
|
||||
return tempStoreLifetimeSeconds;
|
||||
}
|
||||
|
||||
public void setTempStoreLifetimeSeconds(int tempStoreLifetimeSeconds) {
|
||||
this.tempStoreLifetimeSeconds = tempStoreLifetimeSeconds;
|
||||
}
|
||||
|
||||
public static class StorageConfig{
|
||||
private StorageType type;
|
||||
private String basePath;
|
||||
|
||||
public StorageType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(StorageType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getBasePath() {
|
||||
return basePath;
|
||||
}
|
||||
|
||||
public void setBasePath(String basePath) {
|
||||
this.basePath = basePath;
|
||||
}
|
||||
}
|
||||
|
||||
public static class StaticFilesConfig{
|
||||
private String externalUrls;
|
||||
private String semantics;
|
||||
private String h2020template;
|
||||
private String h2020DatasetTemplate;
|
||||
private String pidLinks;
|
||||
|
||||
public String getExternalUrls() {
|
||||
return externalUrls;
|
||||
}
|
||||
|
||||
public void setExternalUrls(String externalUrls) {
|
||||
this.externalUrls = externalUrls;
|
||||
}
|
||||
|
||||
public String getSemantics() {
|
||||
return semantics;
|
||||
}
|
||||
|
||||
public void setSemantics(String semantics) {
|
||||
this.semantics = semantics;
|
||||
}
|
||||
|
||||
public String getH2020template() {
|
||||
return h2020template;
|
||||
}
|
||||
|
||||
public void setH2020template(String h2020template) {
|
||||
this.h2020template = h2020template;
|
||||
}
|
||||
|
||||
public String getH2020DatasetTemplate() {
|
||||
return h2020DatasetTemplate;
|
||||
}
|
||||
|
||||
public void setH2020DatasetTemplate(String h2020DatasetTemplate) {
|
||||
this.h2020DatasetTemplate = h2020DatasetTemplate;
|
||||
}
|
||||
|
||||
public String getPidLinks() {
|
||||
return pidLinks;
|
||||
}
|
||||
|
||||
public void setPidLinks(String pidLinks) {
|
||||
this.pidLinks = pidLinks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package eu.eudat.service.storage;
|
||||
|
||||
import eu.eudat.commons.enums.StorageType;
|
||||
import eu.eudat.model.StorageFile;
|
||||
import eu.eudat.model.persist.StorageFilePersist;
|
||||
import gr.cite.tools.fieldset.FieldSet;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface StorageFileService extends ApplicationListener<ApplicationReadyEvent> {
|
||||
StorageFile persistBytes(StorageFilePersist model, byte[] payload, FieldSet fields) throws IOException;
|
||||
StorageFile persistString(StorageFilePersist model, String payload, FieldSet fields, Charset charset) throws IOException;
|
||||
boolean moveToStorage(UUID fileId, StorageType storageType);
|
||||
boolean copyToStorage(UUID fileId, StorageType storageType);
|
||||
|
||||
boolean exists(UUID fileId);
|
||||
|
||||
boolean fileRefExists(String fileRef, StorageType storageType);
|
||||
|
||||
void updatePurgeAt(UUID fileId, Instant purgeAt);
|
||||
boolean purgeSafe(UUID fileId);
|
||||
String readAsTextSafe(UUID fileId, Charset charset);
|
||||
byte[] readAsBytesSafe(UUID fileId);
|
||||
String readByFileRefAsTextSafe(String fileRef, StorageType storageType, Charset charset);
|
||||
byte[] readByFileRefAsBytesSafe(String fileRef, StorageType storageType);
|
||||
}
|
|
@ -0,0 +1,281 @@
|
|||
package eu.eudat.service.storage;
|
||||
|
||||
import eu.eudat.authorization.AuthorizationFlags;
|
||||
import eu.eudat.authorization.Permission;
|
||||
import eu.eudat.commons.enums.StorageFilePermission;
|
||||
import eu.eudat.commons.enums.StorageType;
|
||||
import eu.eudat.commons.scope.user.UserScope;
|
||||
import eu.eudat.data.StorageFileEntity;
|
||||
import eu.eudat.model.Description;
|
||||
import eu.eudat.model.StorageFile;
|
||||
import eu.eudat.model.builder.StorageFileBuilder;
|
||||
import eu.eudat.model.persist.StorageFilePersist;
|
||||
import gr.cite.commons.web.authz.service.AuthorizationService;
|
||||
import gr.cite.tools.data.builder.BuilderFactory;
|
||||
import gr.cite.tools.exception.MyApplicationException;
|
||||
import gr.cite.tools.fieldset.BaseFieldSet;
|
||||
import gr.cite.tools.fieldset.FieldSet;
|
||||
import gr.cite.tools.logging.LoggerService;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.Instant;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
public class StorageFileServiceImpl implements StorageFileService {
|
||||
|
||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(StorageFileServiceImpl.class));
|
||||
private final EntityManager entityManager;
|
||||
private final AuthorizationService authorizationService;
|
||||
private final BuilderFactory builderFactory;
|
||||
private final UserScope userScope;
|
||||
private final StorageFileProperties config;
|
||||
|
||||
@Autowired
|
||||
public StorageFileServiceImpl(
|
||||
EntityManager entityManager,
|
||||
AuthorizationService authorizationService,
|
||||
BuilderFactory builderFactory,
|
||||
UserScope userScope,
|
||||
StorageFileProperties config
|
||||
) {
|
||||
this.entityManager = entityManager;
|
||||
this.authorizationService = authorizationService;
|
||||
this.builderFactory = builderFactory;
|
||||
this.userScope = userScope;
|
||||
this.config = config;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationReadyEvent event) {
|
||||
this.bootstrap();
|
||||
}
|
||||
|
||||
private void bootstrap() {
|
||||
if (this.config.getStorages() != null) {
|
||||
for (StorageFileProperties.StorageConfig storage : this.config.getStorages()) {
|
||||
Path path = Paths.get(storage.getBasePath());
|
||||
if (!Files.exists(path)) {
|
||||
try {
|
||||
Files.createDirectories(path);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageFile persistBytes(StorageFilePersist model, byte[] payload, FieldSet fields) throws IOException {
|
||||
StorageFileEntity storageFile = this.buildDataEntry(model);
|
||||
|
||||
File file = ResourceUtils.getFile(this.filePath(storageFile.getFileRef(), storageFile.getStorageType()));
|
||||
if (!file.exists()) throw new FileAlreadyExistsException(storageFile.getName());
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||
fos.write(payload);
|
||||
}
|
||||
|
||||
this.entityManager.persist(storageFile);
|
||||
this.entityManager.flush();
|
||||
return this.builderFactory.builder(StorageFileBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).build(BaseFieldSet.build(fields, Description._id), storageFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageFile persistString(StorageFilePersist model, String payload, FieldSet fields, Charset charset) throws IOException {
|
||||
return this.persistBytes(model, payload.getBytes(charset), fields);
|
||||
}
|
||||
|
||||
private StorageFileEntity buildDataEntry(StorageFilePersist model) {
|
||||
|
||||
StorageFileEntity data = new StorageFileEntity();
|
||||
data.setFileRef(UUID.randomUUID().toString().replaceAll("-", "").toLowerCase(Locale.ROOT));
|
||||
data.setName(model.getName());
|
||||
data.setOwnerId(model.getOwnerId());
|
||||
data.setExtension(model.getExtension());
|
||||
data.setStorageType(model.getStorageType());
|
||||
data.setMimeType(model.getMimeType());
|
||||
data.setCreatedAt(Instant.now());
|
||||
data.setPurgeAt(model.getLifetime() == null ? null : Instant.now().plus(model.getLifetime()));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveToStorage(UUID fileId, StorageType storageType) {
|
||||
try {
|
||||
StorageFileEntity storageFile = this.entityManager.find(StorageFileEntity.class, fileId);
|
||||
if (storageFile == null) return false;
|
||||
this.authorizeForce(storageFile, StorageFilePermission.Read);
|
||||
|
||||
File file = ResourceUtils.getFile(this.filePath(storageFile.getFileRef(), storageFile.getStorageType()));
|
||||
if (!file.exists()) return false;
|
||||
|
||||
File destinationFile = ResourceUtils.getFile(this.filePath(storageFile.getFileRef(), storageFile.getStorageType()));
|
||||
boolean fileCopied = FileCopyUtils.copy(file, destinationFile) > 0;
|
||||
if (!fileCopied) return false;
|
||||
return file.delete();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.warn("problem reading byte content of storage file " + fileId, ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean copyToStorage(UUID fileId, StorageType storageType) {
|
||||
try {
|
||||
StorageFileEntity storageFile = this.entityManager.find(StorageFileEntity.class, fileId);
|
||||
if (storageFile == null) return false;
|
||||
this.authorizeForce(storageFile, StorageFilePermission.Read);
|
||||
|
||||
File file = ResourceUtils.getFile(this.filePath(storageFile.getFileRef(), storageFile.getStorageType()));
|
||||
if (!file.exists()) return false;
|
||||
|
||||
File destinationFile = ResourceUtils.getFile(this.filePath(storageFile.getFileRef(), storageFile.getStorageType()));
|
||||
return FileCopyUtils.copy(file, destinationFile) > 0;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.warn("problem reading byte content of storage file " + fileId, ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(UUID fileId) {
|
||||
try {
|
||||
StorageFileEntity storageFile = this.entityManager.find(StorageFileEntity.class, fileId);
|
||||
if (storageFile == null) return false;
|
||||
this.authorizeForce(storageFile, StorageFilePermission.Read);
|
||||
|
||||
File file = ResourceUtils.getFile(this.filePath(storageFile.getFileRef(), storageFile.getStorageType()));
|
||||
return file.exists();
|
||||
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.warn("problem reading byte content of storage file " + fileId, ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fileRefExists(String fileRef, StorageType storageType) {
|
||||
File file = null;
|
||||
try {
|
||||
file = ResourceUtils.getFile(this.filePath(fileRef, storageType));
|
||||
return file.exists();
|
||||
} catch (Exception ex) {
|
||||
logger.warn("problem reading byte content of storage file " + fileRef, ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePurgeAt(UUID fileId, Instant purgeAt) {
|
||||
|
||||
StorageFileEntity storageFile = this.entityManager.find(StorageFileEntity.class, fileId);
|
||||
if (storageFile == null) return;
|
||||
|
||||
storageFile.setPurgeAt(purgeAt);
|
||||
this.entityManager.merge(storageFile);
|
||||
this.entityManager.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean purgeSafe(UUID fileId) {
|
||||
try {
|
||||
StorageFileEntity storageFile = this.entityManager.find(StorageFileEntity.class, fileId);
|
||||
if (storageFile == null) return false;
|
||||
|
||||
storageFile.setPurgedAt(Instant.now());
|
||||
|
||||
this.entityManager.merge(storageFile);
|
||||
this.entityManager.flush();
|
||||
|
||||
File file = ResourceUtils.getFile(this.filePath(storageFile.getFileRef(), storageFile.getStorageType()));
|
||||
if (!file.exists()) return true;
|
||||
|
||||
return file.delete();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.warn("problem reading byte content of storage file " + fileId, ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readAsTextSafe(UUID fileId, Charset charset) {
|
||||
byte[] bytes = this.readAsBytesSafe(fileId);
|
||||
return bytes == null ? null : new String(bytes, charset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] readAsBytesSafe(UUID fileId) {
|
||||
byte[] bytes = null;
|
||||
try {
|
||||
StorageFileEntity storageFile = this.entityManager.find(StorageFileEntity.class, fileId);
|
||||
if (storageFile == null) return null;
|
||||
this.authorizeForce(storageFile, StorageFilePermission.Read);
|
||||
|
||||
bytes = this.readByFileRefAsBytesSafe(storageFile.getFileRef(), storageFile.getStorageType());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.warn("problem reading byte content of storage file " + fileId, ex);
|
||||
}
|
||||
return bytes;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readByFileRefAsTextSafe(String fileRef, StorageType storageType, Charset charset) {
|
||||
byte[] bytes = this.readByFileRefAsBytesSafe(fileRef, storageType);
|
||||
return bytes == null ? null : new String(bytes, charset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] readByFileRefAsBytesSafe(String fileRef, StorageType storageType) {
|
||||
|
||||
byte[] bytes = null;
|
||||
try {
|
||||
File file = ResourceUtils.getFile(this.filePath(fileRef, storageType));
|
||||
if (!file.exists()) return null;
|
||||
try(InputStream inputStream = new FileInputStream(file)){
|
||||
bytes = inputStream.readAllBytes();
|
||||
};
|
||||
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.warn("problem reading byte content of storage file " + fileRef, ex);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private String filePath(String fileRef, StorageType storageType)
|
||||
{
|
||||
StorageFileProperties.StorageConfig storageFileConfig = this.config.getStorages().stream().filter(x -> storageType.equals(x.getType())).findFirst().orElse(null);
|
||||
if (storageFileConfig == null) throw new MyApplicationException("Storage " + storageType + " not found");
|
||||
return Paths.get(storageFileConfig.getBasePath(), fileRef).toString();
|
||||
}
|
||||
|
||||
private void authorizeForce(StorageFileEntity storageFile, StorageFilePermission storageFilePermission) {
|
||||
if (storageFile.getOwnerId() != null && storageFile.getOwnerId().equals(this.userScope.getUserIdSafe())){
|
||||
return;
|
||||
}
|
||||
this.authorizationService.authorizeForce(Permission.BrowseStorageFile);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue