diff --git a/sources/core/pom.xml b/sources/core/pom.xml
index 29badad..3479cc3 100644
--- a/sources/core/pom.xml
+++ b/sources/core/pom.xml
@@ -22,11 +22,11 @@
tools.dynamia.modules.entityfiles.parent
tools.dynamia.modules
- 7.1.2
+ 7.2.0
Dynamia Modules - EntityFiles - Core
tools.dynamia.modules.entityfiles
- 7.1.2
+ 7.2.0
https://www.dynamia.tools/modules/entityfiles
diff --git a/sources/core/src/main/java/tools/dynamia/modules/entityfile/UploadedFileInfo.java b/sources/core/src/main/java/tools/dynamia/modules/entityfile/UploadedFileInfo.java
index 16e39d1..c818d0e 100644
--- a/sources/core/src/main/java/tools/dynamia/modules/entityfile/UploadedFileInfo.java
+++ b/sources/core/src/main/java/tools/dynamia/modules/entityfile/UploadedFileInfo.java
@@ -115,6 +115,10 @@ public void setContentType(String contentType) {
this.contentType = contentType;
}
+ public boolean hasInputStream() {
+ return inputStream != null;
+ }
+
public InputStream getInputStream() {
if (inputStream == null) {
try {
diff --git a/sources/core/src/main/java/tools/dynamia/modules/entityfile/controller/LocalEntityFileStorageController.java b/sources/core/src/main/java/tools/dynamia/modules/entityfile/controller/LocalEntityFileStorageController.java
new file mode 100644
index 0000000..7b9fb79
--- /dev/null
+++ b/sources/core/src/main/java/tools/dynamia/modules/entityfile/controller/LocalEntityFileStorageController.java
@@ -0,0 +1,34 @@
+package tools.dynamia.modules.entityfile.controller;
+
+import jakarta.servlet.http.HttpServletRequest;
+import org.springframework.core.io.Resource;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestParam;
+import tools.dynamia.integration.sterotypes.Controller;
+import tools.dynamia.modules.entityfile.local.LocalEntityFileStorageHandler;
+
+@Controller
+public class LocalEntityFileStorageController {
+
+ private final LocalEntityFileStorageHandler handler;
+
+ public LocalEntityFileStorageController(LocalEntityFileStorageHandler handler) {
+ this.handler = handler;
+ }
+
+ @GetMapping(value = "/storage/{file}")
+ public ResponseEntity get(@PathVariable String file, @RequestParam("uuid") String uuid, HttpServletRequest request) {
+ var resource = handler.getResource(file, uuid, request);
+ if (resource != null && resource.exists() && resource.isReadable()) {
+ return ResponseEntity.ok()
+ .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
+ .body(resource);
+ } else {
+ return new ResponseEntity<>(HttpStatus.NOT_FOUND);
+ }
+ }
+}
diff --git a/sources/core/src/main/java/tools/dynamia/modules/entityfile/domain/EntityFile.java b/sources/core/src/main/java/tools/dynamia/modules/entityfile/domain/EntityFile.java
index 3a52742..f128e7c 100644
--- a/sources/core/src/main/java/tools/dynamia/modules/entityfile/domain/EntityFile.java
+++ b/sources/core/src/main/java/tools/dynamia/modules/entityfile/domain/EntityFile.java
@@ -32,6 +32,7 @@
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
+
import java.util.List;
@Entity
diff --git a/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorage.java b/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorage.java
index 77be073..fa255e5 100644
--- a/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorage.java
+++ b/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorage.java
@@ -18,6 +18,8 @@
package tools.dynamia.modules.entityfile.local;
import org.springframework.core.env.Environment;
+import tools.dynamia.commons.logger.LoggingService;
+import tools.dynamia.commons.logger.SLF4JLoggingService;
import tools.dynamia.domain.ValidationError;
import tools.dynamia.domain.query.Parameters;
import tools.dynamia.domain.services.CrudService;
@@ -37,6 +39,8 @@
@Service
public class LocalEntityFileStorage implements EntityFileStorage {
+ private final LoggingService logger = new SLF4JLoggingService(LocalEntityFileStorage.class, "Local: ");
+
public static final String ID = "LocalStorage";
private static final String LOCAL_FILES_LOCATION = "LOCAL_FILES_LOCATION";
private static final String LOCAL_USE_HTTPS = "LOCAL_USE_HTTPS";
@@ -71,9 +75,12 @@ public void upload(EntityFile entityFile, UploadedFileInfo fileInfo) {
File realFile = getRealFile(entityFile);
try {
+
IOUtils.copy(fileInfo.getInputStream(), realFile);
entityFile.setSize(realFile.length());
+ logger.info("Uploaded to server: " + realFile);
} catch (IOException e) {
+ logger.error("Error upload local file " + realFile, e);
throw new EntityFileException("Error upload local file " + realFile, e);
}
diff --git a/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorageConfig.java b/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorageConfig.java
index 01560d8..f659ac5 100644
--- a/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorageConfig.java
+++ b/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorageConfig.java
@@ -17,34 +17,16 @@
package tools.dynamia.modules.entityfile.local;
-import java.util.HashMap;
-import java.util.Map;
-
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
-import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
+import tools.dynamia.modules.entityfile.service.EntityFileService;
@Configuration
class LocalEntityFileStorageConfig {
- @Bean
- public SimpleUrlHandlerMapping localHandler() {
-
- ResourceHttpRequestHandler handler = localEntityFileStorageHandler();
-
- Map map = new HashMap<>();
-
- map.put("storage/**", handler);
-
- SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
- mapping.setUrlMap(map);
-
- return mapping;
- }
- @Bean
- public LocalEntityFileStorageHandler localEntityFileStorageHandler() {
- return new LocalEntityFileStorageHandler();
- }
+ @Bean
+ public LocalEntityFileStorageHandler localEntityFileStorageHandler(LocalEntityFileStorage storage, EntityFileService service) {
+ return new LocalEntityFileStorageHandler(storage, service);
+ }
}
diff --git a/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorageHandler.java b/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorageHandler.java
index 5178889..0d1b1ff 100644
--- a/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorageHandler.java
+++ b/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorageHandler.java
@@ -23,7 +23,6 @@
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
-import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
import tools.dynamia.commons.StringUtils;
import tools.dynamia.integration.Containers;
@@ -36,21 +35,21 @@
import tools.dynamia.modules.entityfile.enums.EntityFileType;
import tools.dynamia.modules.entityfile.service.EntityFileService;
-public class LocalEntityFileStorageHandler extends ResourceHttpRequestHandler {
+public class LocalEntityFileStorageHandler {
private static final String UUID = "/uuid/";
- private LocalEntityFileStorage storage;
- private EntityFileService service;
+ private final LocalEntityFileStorage storage;
+ private final EntityFileService service;
private EntityFileAccountProvider accountProvider;
- @Override
- protected Resource getResource(HttpServletRequest request) {
- if (service == null) {
- service = Containers.get().findObject(EntityFileService.class);
- }
- if (storage == null) {
- storage = Containers.get().findObject(LocalEntityFileStorage.class);
- }
+ public LocalEntityFileStorageHandler(LocalEntityFileStorage storage, EntityFileService service) {
+ this.storage = storage;
+ this.service = service;
+ }
+
+
+ public Resource getResource(String fileName, String uuid, HttpServletRequest request) {
+
if (accountProvider == null) {
accountProvider = Containers.get().findObject(EntityFileAccountProvider.class);
@@ -60,23 +59,11 @@ protected Resource getResource(HttpServletRequest request) {
}
File file = null;
- String uuid = getParam(request, "uuid", null);
-
- if (uuid == null) {
- String path = request.getPathInfo();
- if (path.contains(UUID)) {
- uuid = path.substring(path.lastIndexOf(UUID) + UUID.length());
- uuid = StringUtils.removeFilenameExtension(uuid);
- }
- }
-
- if (uuid == null) {
- return null;
- }
-
Long currentAccountId = accountProvider.getAccountId();
EntityFile entityFile = service.getEntityFile(uuid);
+
+
if (entityFile != null && (currentAccountId == null || currentAccountId.equals(0L) || entityFile.isShared() || entityFile.getAccountId().equals(currentAccountId))) {
StoredEntityFile storedEntityFile = storage.download(entityFile);
diff --git a/sources/core/src/main/java/tools/dynamia/modules/entityfile/service/impl/EntityFileServiceImpl.java b/sources/core/src/main/java/tools/dynamia/modules/entityfile/service/impl/EntityFileServiceImpl.java
index b6f7918..79cfb64 100644
--- a/sources/core/src/main/java/tools/dynamia/modules/entityfile/service/impl/EntityFileServiceImpl.java
+++ b/sources/core/src/main/java/tools/dynamia/modules/entityfile/service/impl/EntityFileServiceImpl.java
@@ -18,6 +18,9 @@
package tools.dynamia.modules.entityfile.service.impl;
+import jakarta.persistence.criteria.CriteriaBuilder;
+import jakarta.persistence.criteria.CriteriaQuery;
+import jakarta.persistence.criteria.Root;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -101,7 +104,7 @@ private EntityFile createDir(EntityFile parent, Object targetEntity, String name
@Override
@Transactional
public EntityFile createEntityFile(UploadedFileInfo fileInfo, Object target, String description) {
- logger.info("Creating new entity file for " + target + ", file: " + fileInfo.getFullName());
+ logger.info("Creating new entity file for " + (target != null ? target : "temporal entity") + ", file: " + fileInfo.getFullName());
EntityFile entityFile = new EntityFile();
entityFile.setDescription(description);
entityFile.setContentType(fileInfo.getContentType());
@@ -294,8 +297,11 @@ public void download(EntityFile entityFile, File outputFile) {
@Override
public EntityFile getEntityFile(String uuid) {
try {
- return crudService.findSingle(EntityFile.class, QueryParameters.with("uuid", QueryConditions.eq(uuid))
- .add("accountId", QueryConditions.isNotNull()));
+ CriteriaBuilder cb = entityManager.getCriteriaBuilder();
+ CriteriaQuery query = cb.createQuery(EntityFile.class);
+ Root root = query.from(EntityFile.class);
+ query.select(root).where(cb.equal(root.get("uuid"), uuid));
+ return entityManager.createQuery(query).setMaxResults(1).getSingleResult();
} catch (Exception e) {
logger.error("Error loading entity file with uuid: " + uuid + ". " + e.getMessage(), e);
diff --git a/sources/pom.xml b/sources/pom.xml
index 03a27f8..978a58b 100644
--- a/sources/pom.xml
+++ b/sources/pom.xml
@@ -22,7 +22,7 @@
tools.dynamia.modules
tools.dynamia.modules.entityfiles.parent
pom
- 7.1.2
+ 7.2.0
Dynamia Modules - EntityFiles
https://dynamia.tools/modules/entityfiles
DynamiaTools extension to attach files to entities
@@ -63,9 +63,9 @@
UTF-8
- 5.2.0
+ 5.2.1
3.3.3
- 1.12.771
+ 2.28.11
17
3.13.0
UTF-8
@@ -88,7 +88,7 @@
org.sonatype.plugins
nexus-staging-maven-plugin
- 1.6.13
+ 1.7.0
true
ossrh
@@ -99,7 +99,7 @@
org.apache.maven.plugins
maven-javadoc-plugin
- 3.5.0
+ 3.10.0
false
none
@@ -108,7 +108,7 @@
org.apache.maven.plugins
maven-source-plugin
- 3.3.0
+ 3.3.1
@@ -122,7 +122,7 @@
commons-io
commons-io
- 2.15.1
+ 2.16.1
@@ -175,7 +175,7 @@
org.apache.maven.plugins
maven-gpg-plugin
- 3.0.1
+ 3.1.0
sign-artifacts
diff --git a/sources/s3/pom.xml b/sources/s3/pom.xml
index 41ea7e3..2849e36 100644
--- a/sources/s3/pom.xml
+++ b/sources/s3/pom.xml
@@ -23,12 +23,12 @@
tools.dynamia.modules
tools.dynamia.modules.entityfiles.parent
- 7.1.2
+ 7.2.0
Dynamia Modules - EntityFiles - S3
tools.dynamia.modules.entityfiles.s3
- 7.1.2
+ 7.2.0
https://www.dynamia.tools/modules/entityfiles
@@ -53,8 +53,8 @@
${project.parent.version}
- com.amazonaws
- aws-java-sdk-s3
+ software.amazon.awssdk
+ s3
${aws.version}
diff --git a/sources/s3/src/main/java/tools/dynamia/modules/entityfiles/s3/S3EntityFileStorage.java b/sources/s3/src/main/java/tools/dynamia/modules/entityfiles/s3/S3EntityFileStorage.java
index 618fcd0..a30cf70 100644
--- a/sources/s3/src/main/java/tools/dynamia/modules/entityfiles/s3/S3EntityFileStorage.java
+++ b/sources/s3/src/main/java/tools/dynamia/modules/entityfiles/s3/S3EntityFileStorage.java
@@ -17,23 +17,17 @@
package tools.dynamia.modules.entityfiles.s3;
-import com.amazonaws.AmazonClientException;
-import com.amazonaws.AmazonServiceException;
-import com.amazonaws.ClientConfiguration;
-import com.amazonaws.Protocol;
-import com.amazonaws.auth.AWSCredentials;
-import com.amazonaws.auth.AWSStaticCredentialsProvider;
-import com.amazonaws.auth.BasicAWSCredentials;
-import com.amazonaws.regions.Regions;
-import com.amazonaws.services.s3.AmazonS3;
-import com.amazonaws.services.s3.AmazonS3ClientBuilder;
-import com.amazonaws.services.s3.model.CannedAccessControlList;
-import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
-import com.amazonaws.services.s3.model.ObjectMetadata;
-import com.amazonaws.services.s3.model.PutObjectRequest;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
+import software.amazon.awssdk.core.async.AsyncRequestBody;
+import software.amazon.awssdk.services.s3.S3AsyncClient;
+import software.amazon.awssdk.services.s3.model.ObjectCannedACL;
+import software.amazon.awssdk.services.s3.model.PutObjectRequest;
+import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;
import tools.dynamia.commons.SimpleCache;
import tools.dynamia.commons.logger.LoggingService;
import tools.dynamia.commons.logger.SLF4JLoggingService;
@@ -46,13 +40,16 @@
import tools.dynamia.modules.entityfile.domain.EntityFile;
import tools.dynamia.modules.entityfile.enums.EntityFileType;
-import java.io.ByteArrayInputStream;
import java.io.File;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
+import java.time.Duration;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
/**
* {@link EntityFileStorage} implementation that store files in Amazon S3 service.
@@ -65,14 +62,18 @@ public class S3EntityFileStorage implements EntityFileStorage {
public static final String AWS_ACCESS_KEY_ID = "AWS_ACCESS_KEY_ID";
public static final String AWS_SECRET_KEY = "AWS_SECRET_KEY";
public static final String AWS_S3_ENDPOINT = "AWS_S3_ENDPOINT";
+ public static final String AWS_S3_REGION = "AWS_S3_REGION";
public static final String AWS_S3_BUCKET = "AWS_S3_BUCKET";
- private final LoggingService logger = new SLF4JLoggingService(S3EntityFileStorage.class);
+ private static final Logger log = LoggerFactory.getLogger(S3EntityFileStorage.class);
+ private final LoggingService logger = new SLF4JLoggingService(S3EntityFileStorage.class, "S3: ");
private final SimpleCache URL_CACHE = new SimpleCache<>();
private final SimpleCache PARAMS_CACHE = new SimpleCache<>();
public static final String ID = "AWSS3Storage";
+ private S3AsyncClient s3Client;
+ private final ExecutorService executorService = Executors.newCachedThreadPool();
@Autowired
private Environment environment;
@@ -88,6 +89,13 @@ public String getName() {
return "AWS S3 Storage";
}
+ /**
+ * Upload entity file to S3 bucket
+ *
+ * @param entityFile the entity file
+ * @param fileInfo the uploade file info
+ * @return the S3 client
+ */
@Override
public void upload(EntityFile entityFile, UploadedFileInfo fileInfo) {
try {
@@ -97,49 +105,72 @@ public void upload(EntityFile entityFile, UploadedFileInfo fileInfo) {
// Metadata
- File tmpFile = null;
+ File fileToUpload;
long sourceLength = 0;
long length = fileInfo.getLength();
if (fileInfo.getSource() instanceof File file) {
sourceLength = file.length();
- tmpFile = file;
- } else if (fileInfo.getInputStream() instanceof Path path) {
+ fileToUpload = file;
+ } else if (fileInfo.getSource() instanceof Path path) {
sourceLength = path.toFile().length();
- tmpFile = path.toFile();
+ fileToUpload = path.toFile();
+ } else {
+ fileToUpload = null;
}
if (length <= 0 && sourceLength > 0) {
length = sourceLength;
}
- ObjectMetadata metadata = new ObjectMetadata();
- metadata.addUserMetadata("accountId", entityFile.getAccountId().toString());
- metadata.addUserMetadata("uuid", entityFile.getUuid());
- metadata.addUserMetadata("creator", entityFile.getCreator());
- metadata.addUserMetadata("databaseId", String.valueOf(entityFile.getId()));
- metadata.setContentLength(length);
- metadata.setContentType(URLConnection.guessContentTypeFromName(entityFile.getName()));
+ final var metadata = Map.of(
+ "accountId", entityFile.getAccountId() != null ? entityFile.getAccountId().toString() : "",
+ "uuid", entityFile.getUuid(),
+ "creator", entityFile.getCreator() != null ? entityFile.getCreator() : "anonymous",
+ "databaseId", entityFile.getId() != null ? String.valueOf(entityFile.getId()) : ""
+ );
+ final var contentType = URLConnection.guessContentTypeFromName(entityFile.getName());
final var key = folder + fileName;
final var bucket = getBucketName();
- PutObjectRequest request = new PutObjectRequest(bucket, key, fileInfo.getInputStream(), metadata);
- request.setCannedAcl(entityFile.isShared() ? CannedAccessControlList.PublicRead : CannedAccessControlList.Private);
-
- var result = getConnection().putObject(request);
- logger.info("EntityFile " + entityFile + " uploaded to S3 Bucket " + getBucketName() + " / " + key);
-
-
- if (tmpFile != null && tmpFile.delete()) {
- logger.info("Deleted temporal file: " + tmpFile);
+ PutObjectRequest request = PutObjectRequest.builder()
+ .bucket(bucket)
+ .key(key)
+ .metadata(metadata)
+ .contentLength(length)
+ .contentType(contentType)
+ .acl(entityFile.isShared() ? ObjectCannedACL.PUBLIC_READ : ObjectCannedACL.PRIVATE)
+ .build();
+
+
+ AsyncRequestBody body = null;
+ if (fileToUpload != null && fileToUpload.exists()) {
+ logger.info("Uploading file " + fileToUpload.getPath() + " to " + key);
+ body = AsyncRequestBody.fromFile(fileToUpload);
+ } else if (fileInfo.hasInputStream()) {
+ logger.info("Uploading input stream from " + fileInfo.getFullName() + " to " + key);
+ body = AsyncRequestBody.fromInputStream(fileInfo.getInputStream(), length, executorService);
}
+ getClient().putObject(request, body)
+ .whenComplete((response, throwable) -> {
+ if (throwable != null) {
+ logger.error("Error uploading entity file " + entityFile.getName() + " to S3", throwable);
+ throw new EntityFileException("Error uploading file " + entityFile.getName(), throwable);
+ } else {
+ logger.info("Entity file " + entityFile.getName() + " uploaded");
+ }
+
+ if (fileToUpload != null && fileToUpload.delete()) {
+ logger.info("Deleted temporal file: " + fileToUpload);
+ }
+ });
- } catch (AmazonClientException amazonClientException) {
- logger.error("Error uploading entity file " + entityFile.getName() + " to S3", amazonClientException);
- throw new EntityFileException("Error uploading file " + entityFile.getName(), amazonClientException);
+ } catch (Exception e) {
+ logger.error("Error sending PUT request for entity file " + entityFile.getName() + " to S3", e);
+ throw new EntityFileException("Error sending PUT request fo file " + entityFile.getName(), e);
}
}
@@ -163,21 +194,19 @@ public StoredEntityFile download(EntityFile entityFile) {
return new S3StoredEntityFile(entityFile, url, new File(fileName));
}
- private String generateSignedURL(String bucketName, String fileName) {
- try {
- GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, fileName);
- return getConnection().generatePresignedUrl(request).toString();
+ protected String generateSignedURL(String bucketName, String fileName) {
+
+
+ PresignedGetObjectRequest presignedRequest = S3Utils.generatePresignedObjetRequest(bucketName, fileName, Duration.ofMinutes(30));
+ logger.info("Presigned URL: " + presignedRequest.url().toString());
+ logger.info("HTTP method: " + presignedRequest.httpRequest().method());
+
+ return presignedRequest.url().toExternalForm();
- } catch (AmazonClientException amazonClientException) {
- logger.error("Error generating URL for " + bucketName + " => " + fileName, amazonClientException);
- return "#";
- }
}
private String generateStaticURL(String bucketName, String fileName) {
- String endpoint = getEndpoint();
- fileName = fileName.replace(" ", "%20");
- return String.format("https://%s.%s/%s", bucketName, endpoint, fileName);
+ return S3Utils.generateStaticURL(bucketName, fileName, getRegion());
}
@@ -204,25 +233,30 @@ private String getFileName(EntityFile entityFile) {
return subfolder + storedFileName;
}
- private AmazonS3 getConnection() {
- ClientConfiguration clientConfig = new ClientConfiguration();
- clientConfig.setProtocol(Protocol.HTTPS);
+ /**
+ * Get or build a S3 async client using static credentials
+ *
+ * @return S3 Async client
+ */
+ protected S3AsyncClient getClient() {
+
+ if (s3Client == null) {
+ s3Client = S3Utils.buildS3AsyncClient(getAccessKey(), getSecretKey(), getRegion())
+ .build();
+ }
+ return s3Client;
- AWSCredentials credentials = new BasicAWSCredentials(getAccessKey(), getSecretKey());
- return AmazonS3ClientBuilder.standard()
- .withCredentials(new AWSStaticCredentialsProvider(credentials))
- .withRegion(Regions.US_EAST_1)
- .withRegionalUsEast1EndpointEnabled(true)
- .withClientConfiguration(clientConfig)
- .build();
}
- private String getAccountFolderName(Long accountId) {
+ protected String getAccountFolderName(Long accountId) {
return "account" + accountId + "/";
}
- private String generateThumbnailURL(EntityFile entityFile, int w, int h) {
+ /**
+ * Generate thumbnail url
+ */
+ protected String generateThumbnailURL(EntityFile entityFile, int w, int h) {
if (entityFile.getType() == EntityFileType.IMAGE || EntityFileType.getFileType(entityFile.getExtension()) == EntityFileType.IMAGE) {
String urlKey = entityFile.getUuid() + w + "x" + h;
String url = URL_CACHE.get(urlKey);
@@ -244,10 +278,13 @@ private String generateThumbnailURL(EntityFile entityFile, int w, int h) {
}
}
- private void createAndUploadThumbnail(EntityFile entityFile, String bucketName, String folder, String fileName, String thumbfileName,
- int w, int h) throws AmazonClientException {
+ /**
+ * Create and upload thumbnail
+ */
+ protected void createAndUploadThumbnail(EntityFile entityFile, String bucketName, String folder, String fileName, String thumbfileName,
+ int w, int h) {
try {
- final var key = folder + fileName;
+
File localDestination = File.createTempFile(System.currentTimeMillis() + "file", entityFile.getName());
File localThumbDestination = File.createTempFile(System.currentTimeMillis() + "thumb", entityFile.getName());
@@ -259,20 +296,33 @@ private void createAndUploadThumbnail(EntityFile entityFile, String bucketName,
// metadata
- ObjectMetadata metadata = new ObjectMetadata();
- metadata.addUserMetadata("thumbnail", "true");
- metadata.addUserMetadata("description", entityFile.getDescription());
- metadata.addUserMetadata("uuid", entityFile.getUuid());
- metadata.addUserMetadata("width", String.valueOf(w));
- metadata.addUserMetadata("height", String.valueOf(h));
- metadata.setContentType("image/" + entityFile.getExtension());
- metadata.setContentLength(localThumbDestination.length());
-
- PutObjectRequest request = new PutObjectRequest(bucketName, folder + thumbfileName, localThumbDestination);
- request.setMetadata(metadata);
- request.setCannedAcl(CannedAccessControlList.PublicRead);
-
- getConnection().putObject(request);
+ var metadata = Map.of(
+ "thumbnail", "true",
+ "description", entityFile.getDescription(),
+ "uuid", entityFile.getUuid(),
+ "width", String.valueOf(w),
+ "height", String.valueOf(h));
+
+ String key = folder + thumbfileName;
+ PutObjectRequest request = PutObjectRequest.builder()
+ .bucket(bucketName)
+ .key(key)
+ .contentLength(localThumbDestination.length())
+ .contentType("image/" + entityFile.getExtension())
+ .acl(ObjectCannedACL.PUBLIC_READ)
+ .build();
+
+
+ getClient().putObject(request, AsyncRequestBody.fromFile(localThumbDestination))
+ .whenComplete((putObjectResponse, throwable) -> {
+ if (throwable != null) {
+ logger.error("Error uploading thumbnail " + localDestination, throwable);
+ } else {
+ logger.info("Thumbnail uploaded " + key);
+ }
+
+ localThumbDestination.delete();
+ });
} catch (Exception e) {
logger.error("Error creating thumbnail for " + entityFile.getName() + " " + w + "x" + h + " " + fileName, e);
@@ -280,23 +330,23 @@ private void createAndUploadThumbnail(EntityFile entityFile, String bucketName,
}
public boolean objectExists(String bucketName, String key) {
- try {
- getConnection().getObjectMetadata(bucketName, key);
- } catch (AmazonServiceException e) {
- return false;
- }
- return true;
+ return S3Utils.objectExists(getClient(), bucketName, key);
}
@Override
public void delete(EntityFile entityFile) {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
-
- public void resetConnection() {
-
+ String folder = getAccountFolderName(entityFile.getAccountId());
+ String key = folder + getFileName(entityFile);
+
+ S3Utils.deleteFile(getClient(), getBucketName(), key)
+ .whenComplete((deleteObjectResponse, throwable) -> {
+ if (throwable != null) {
+ logger.error("Error deleting entity file " + entityFile.getName() + " from S3", throwable);
+ } else {
+ logger.info("Entity file " + entityFile.getName() + " deleted from S3");
+ }
+ });
}
@@ -312,15 +362,23 @@ public String getAccessKey() {
return getParameter(AWS_ACCESS_KEY_ID);
}
- private String getParameter(String name) {
- var param = PARAMS_CACHE.getOrLoad(name, s -> {
+ public String getRegion() {
+ var region = getParameter(AWS_S3_REGION);
+ if (region == null || region.isBlank()) {
+ region = "us-east-1";
+ }
+ return region;
+ }
+
+
+ protected String getParameter(String name) {
+ return PARAMS_CACHE.getOrLoad(name, s -> {
var value = ApplicationParameters.get().getValue(name);
if (value == null) {
value = environment.getProperty(name);
}
return value;
});
- return param;
}
public String getSecretKey() {
@@ -331,6 +389,7 @@ public String getSecretKey() {
public void reloadParams() {
PARAMS_CACHE.clear();
URL_CACHE.clear();
+ s3Client = null;
}
class S3StoredEntityFile extends StoredEntityFile {
diff --git a/sources/s3/src/main/java/tools/dynamia/modules/entityfiles/s3/S3Utils.java b/sources/s3/src/main/java/tools/dynamia/modules/entityfiles/s3/S3Utils.java
new file mode 100644
index 0000000..4f5fc82
--- /dev/null
+++ b/sources/s3/src/main/java/tools/dynamia/modules/entityfiles/s3/S3Utils.java
@@ -0,0 +1,224 @@
+package tools.dynamia.modules.entityfiles.s3;
+
+import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
+import software.amazon.awssdk.auth.credentials.AwsCredentials;
+import software.amazon.awssdk.core.async.AsyncRequestBody;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.s3.S3AsyncClient;
+import software.amazon.awssdk.services.s3.S3AsyncClientBuilder;
+import software.amazon.awssdk.services.s3.model.*;
+import software.amazon.awssdk.services.s3.presigner.S3Presigner;
+import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;
+import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;
+import tools.dynamia.commons.StringUtils;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.time.Duration;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Utility class to work AWS S3 Buckets
+ */
+public class S3Utils {
+
+
+ /**
+ * Get credentials from access key and secret key
+ *
+ * @param accessKey the access key
+ * @param secretKey the secret key
+ * @return the aws credentials
+ */
+ public static AwsCredentials getCredentials(String accessKey, String secretKey) {
+ return AwsBasicCredentials.create(accessKey, secretKey);
+ }
+
+ /**
+ * Build S3AsyncClient
+ *
+ * @param accessKey the access key
+ * @param secretKey the secret key
+ * @param region the region
+ * @return the S3AsyncClient
+ */
+ public static S3AsyncClientBuilder buildS3AsyncClient(String accessKey, String secretKey, String region) {
+ return S3AsyncClient.builder()
+ .credentialsProvider(() -> getCredentials(accessKey, secretKey))
+ .region(Region.of(region));
+
+ }
+
+ /**
+ * Upload file to S3 bucket
+ *
+ * @param s3Client the S3AsyncClient
+ * @param bucketName the bucket name
+ * @param key the key
+ * @param file the file
+ * @return the CompletableFuture
+ */
+ public static CompletableFuture uploadFile(S3AsyncClient s3Client, String bucketName, String key, File file) {
+ return s3Client.putObject(PutObjectRequest.builder()
+ .bucket(bucketName)
+ .key(key)
+ .build(), AsyncRequestBody.fromFile(file));
+ }
+
+ /**
+ * Delete file from S3 bucket
+ *
+ * @param s3Cliente the S3AsyncClient
+ * @param bucketName the bucket name
+ * @param key the key
+ * @return the CompletableFuture
+ */
+ public static CompletableFuture deleteFile(S3AsyncClient s3Cliente, String bucketName, String key) {
+ DeleteObjectRequest request = DeleteObjectRequest.builder()
+ .bucket(bucketName)
+ .key(key)
+ .build();
+
+ return s3Cliente.deleteObject(request);
+ }
+
+ /**
+ * Generate presigned URL for S3 object
+ *
+ * @param bucketName the bucket name
+ * @param key the key
+ * @param duration the duration
+ * @return the presigned URL
+ */
+ public static PresignedGetObjectRequest generatePresignedObjetRequest(String bucketName, String key, Duration duration) {
+
+ try (S3Presigner presigner = S3Presigner.create()) {
+
+ GetObjectRequest objectRequest = GetObjectRequest.builder()
+ .bucket(bucketName)
+ .key(key)
+ .build();
+
+ GetObjectPresignRequest presignRequest = GetObjectPresignRequest.builder()
+ .signatureDuration(duration)
+ .getObjectRequest(objectRequest)
+ .build();
+
+ return presigner.presignGetObject(presignRequest);
+ }
+ }
+
+ /**
+ * Generate static URL for S3 object
+ *
+ * @param bucketName the bucket name
+ * @param key the key
+ * @param region the region
+ * @return the static URL
+ */
+ public static String generateStaticURL(String bucketName, String key, String region) {
+ String endpoint = "s3." + region + ".amazonaws.com";
+ key = key.replace(" ", "%20");
+ return String.format("https://%s.%s/%s", bucketName, endpoint, key);
+ }
+
+ /**
+ * Get regions
+ *
+ * @return the list of regions
+ */
+ public static List getRegions() {
+ return Region.regions().stream().map(Region::id).toList();
+ }
+
+ /**
+ * Check if object exists in S3 bucket
+ *
+ * @param client the S3AsyncClient
+ * @param bucketName the bucket name
+ * @param key the key
+ * @return true if object exists, false otherwise
+ */
+ public static boolean objectExists(S3AsyncClient client, String bucketName, String key) {
+ try {
+ getObjectAttributes(client, bucketName, key).wait();
+ } catch (Exception e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Get object attributes
+ *
+ * @param client the S3AsyncClient
+ * @param bucketName the bucket name
+ * @param key the key
+ * @return the CompletableFuture
+ */
+ public static CompletableFuture getObjectAttributes(S3AsyncClient client, String bucketName, String key) {
+ return client.getObjectAttributes(builder -> builder.bucket(bucketName).key(key));
+ }
+
+ /**
+ * Head object
+ *
+ * @param client the S3AsyncClient
+ * @param bucketName the bucket name
+ * @param key the key
+ * @return the CompletableFuture
+ */
+ public static CompletableFuture headObject(S3AsyncClient client, String bucketName, String key) {
+ return client.headObject(builder -> builder.bucket(bucketName).key(key));
+ }
+
+ /**
+ * Download file
+ *
+ * @param client the S3AsyncClient
+ * @param bucketName the bucket name
+ * @param key the key
+ * @param destination the destination
+ * @return the CompletableFuture
+ */
+ public static CompletableFuture downloadFile(S3AsyncClient client, String bucketName, String key, File destination) {
+ return downloadFile(client, bucketName, key, destination.toPath());
+ }
+
+ /**
+ * Download file
+ *
+ * @param client the S3AsyncClient
+ * @param bucketName the bucket name
+ * @param key the key
+ * @param destination the destination
+ * @return the CompletableFuture
+ */
+ public static CompletableFuture downloadFile(S3AsyncClient client, String bucketName, String key, Path destination) {
+ GetObjectRequest request = GetObjectRequest
+ .builder()
+ .bucket(bucketName)
+ .key(key)
+ .build();
+ return client.getObject(request, destination);
+ }
+
+ /**
+ * Download file
+ *
+ * @param client the S3AsyncClient
+ * @param bucketName the bucket name
+ * @param key the key
+ * @return the File
+ */
+ public static File downloadFile(S3AsyncClient client, String bucketName, String key) {
+ try {
+ File tmpFile = File.createTempFile("tmpFile", StringUtils.getFilenameExtension(key));
+ downloadFile(client, bucketName, key, tmpFile).wait();
+ return tmpFile;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/sources/ui/pom.xml b/sources/ui/pom.xml
index 33e9d98..8ed45fc 100644
--- a/sources/ui/pom.xml
+++ b/sources/ui/pom.xml
@@ -22,11 +22,11 @@
tools.dynamia.modules.entityfiles.parent
tools.dynamia.modules
- 7.1.2
+ 7.2.0
Dynamia Modules - EntityFiles UI
tools.dynamia.modules.entityfiles.ui
- 7.1.2
+ 7.2.0
https://www.dynamia.tools/modules/entityfiles
diff --git a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/EntityFileController.java b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/EntityFileController.java
index 62b1328..c65020a 100644
--- a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/EntityFileController.java
+++ b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/EntityFileController.java
@@ -30,16 +30,18 @@
import tools.dynamia.zk.crud.ui.EntityTreeNode;
import tools.dynamia.zk.crud.ui.LazyEntityTreeNode;
+import java.io.Serial;
import java.util.List;
public class EntityFileController extends TreeCrudController {
- private EntityFileService service;
+ private final EntityFileService service;
private Object targetEntity;
/**
*
*/
+ @Serial
private static final long serialVersionUID = 7926996145692421296L;
public EntityFileController() {
diff --git a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/EntityFilesInstaller.java b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/EntityFilesModuleProvider.java
similarity index 77%
rename from sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/EntityFilesInstaller.java
rename to sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/EntityFilesModuleProvider.java
index 7cecab6..7ed9e94 100644
--- a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/EntityFilesInstaller.java
+++ b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/EntityFilesModuleProvider.java
@@ -1,49 +1,50 @@
-
-/*
- * Copyright (C) 2023 Dynamia Soluciones IT S.A.S - NIT 900302344-1
- * Colombia / South America
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package tools.dynamia.modules.entityfile.ui;
-
-import tools.dynamia.crud.cfg.ConfigPage;
-import tools.dynamia.integration.sterotypes.Provider;
-import tools.dynamia.navigation.Module;
-import tools.dynamia.navigation.ModuleProvider;
-import tools.dynamia.navigation.PageGroup;
-
-
-/**
- *
- * @author Mario Serrano Leones
- */
-@Provider
-public class EntityFilesInstaller implements ModuleProvider {
-
- @Override
- public Module getModule() {
- Module module = Module.getRef("system");
-
- PageGroup pg = new PageGroup("config", "Configuracion");
- module.addPageGroup(pg);
- {
- pg.addPage(new ConfigPage("entityFile", "Archivos", "EntityFileCFG"));
-
- }
-
- return module;
- }
-
-}
+
+/*
+ * Copyright (C) 2023 Dynamia Soluciones IT S.A.S - NIT 900302344-1
+ * Colombia / South America
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tools.dynamia.modules.entityfile.ui;
+
+import tools.dynamia.crud.cfg.ConfigPage;
+import tools.dynamia.integration.sterotypes.Provider;
+import tools.dynamia.navigation.Module;
+import tools.dynamia.navigation.ModuleProvider;
+import tools.dynamia.navigation.PageGroup;
+
+
+/**
+ * @author Mario Serrano Leones
+ */
+@Provider
+public class EntityFilesModuleProvider implements ModuleProvider {
+
+ @Override
+ public Module getModule() {
+ Module module = Module.getRef("system")
+ .name("System")
+ .icon("settings");
+
+ PageGroup pg = new PageGroup("config", "Configuration");
+ module.addPageGroup(pg);
+ {
+ pg.addPage(new ConfigPage("entityFile", "Entity Files", "EntityFileCFG"));
+
+ }
+
+ return module;
+ }
+
+}
diff --git a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/actions/ViewFileURLAction.java b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/actions/ViewFileURLAction.java
index 9e2b1ab..0d90b7b 100644
--- a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/actions/ViewFileURLAction.java
+++ b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/actions/ViewFileURLAction.java
@@ -21,6 +21,7 @@
import tools.dynamia.actions.ActionGroup;
import tools.dynamia.actions.InstallAction;
import tools.dynamia.actions.ReadableOnly;
+import tools.dynamia.ui.UIMessages;
@InstallAction
public class ViewFileURLAction extends AbstractEntityFileAction implements ReadableOnly {
@@ -35,7 +36,8 @@ public ViewFileURLAction() {
@Override
public void actionPerformed(EntityFileActionEvent evt) {
if (evt.getEntityFile() != null) {
- Messagebox.show(evt.getEntityFile().getStoredEntityFile().getUrl());
+ String url = evt.getEntityFile().getStoredEntityFile().getUrl();
+ UIMessages.showMessageDialog("" + url + "
");
}
}
}
diff --git a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/DirectoryBox.java b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/DirectoryBox.java
index f50eace..68e8bed 100644
--- a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/DirectoryBox.java
+++ b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/DirectoryBox.java
@@ -27,6 +27,8 @@
import tools.dynamia.zk.BindingComponentIndex;
import tools.dynamia.zk.ComponentAliasIndex;
+import java.io.Serial;
+
/**
*
* @author Mario Serrano Leones
@@ -36,24 +38,22 @@ public class DirectoryBox extends Bandbox {
/**
*
*/
- private static final long serialVersionUID = -7769832324226733919L;
+ @Serial
+ private static final long serialVersionUID = -7769832324226733919L;
static {
BindingComponentIndex.getInstance().put("value", DirectoryBox.class);
ComponentAliasIndex.getInstance().add(DirectoryBox.class);
}
- private DirectoryExplorer explorer;
- private Bandpopup popup;
-
public DirectoryBox() {
this(null);
}
public DirectoryBox(String value) throws WrongValueException {
super(value);
- explorer = new DirectoryExplorer();
- popup = new Bandpopup();
+ DirectoryExplorer explorer = new DirectoryExplorer();
+ Bandpopup popup = new Bandpopup();
popup.appendChild(explorer);
popup.setWidth("400px");
diff --git a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/DirectoryExplorer.java b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/DirectoryExplorer.java
index 02d6195..49c6c10 100644
--- a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/DirectoryExplorer.java
+++ b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/DirectoryExplorer.java
@@ -76,8 +76,8 @@ private void init() {
private void initModel() {
FileInfo file = new FileInfo(new File("/"));
- rootNode = new EntityTreeNode(file);
- treeModel = new EntityTreeModel(rootNode);
+ rootNode = new EntityTreeNode<>(file);
+ treeModel = new EntityTreeModel<>(rootNode);
for (EntityTreeNode entityTreeNode : getSubdirectories(file)) {
rootNode.addChild(entityTreeNode);
}
@@ -86,18 +86,14 @@ private void initModel() {
}
private Collection> getSubdirectories(FileInfo file) {
- File[] subs = file.getFile().listFiles(new FileFilter() {
-
- @Override
- public boolean accept(File pathname) {
- if (pathname.isDirectory()) {
- if (!isShowHiddenFolders()) {
- return !pathname.isHidden() && !pathname.getName().startsWith(".");
- }
- return true;
+ File[] subs = file.getFile().listFiles(pathname -> {
+ if (pathname.isDirectory()) {
+ if (!isShowHiddenFolders()) {
+ return !pathname.isHidden() && !pathname.getName().startsWith(".");
}
- return false;
+ return true;
}
+ return false;
});
List> subdirectories = new ArrayList>();
@@ -107,13 +103,7 @@ public boolean accept(File pathname) {
}
}
- Collections.sort(subdirectories, new Comparator>() {
-
- @Override
- public int compare(EntityTreeNode o1, EntityTreeNode o2) {
- return o1.getData().getName().compareTo(o2.getData().getName());
- }
- });
+ subdirectories.sort(Comparator.comparing(o -> o.getData().getName()));
return subdirectories;
}
diff --git a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileDownloadlink.java b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileDownloadlink.java
index 4c12207..24fb126 100644
--- a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileDownloadlink.java
+++ b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileDownloadlink.java
@@ -18,6 +18,7 @@
package tools.dynamia.modules.entityfile.ui.components;
import java.io.FileInputStream;
+import java.io.Serial;
import java.net.URL;
import org.zkoss.util.media.AMedia;
@@ -42,6 +43,7 @@ public class EntityFileDownloadlink extends Toolbarbutton {
/**
*
*/
+ @Serial
private static final long serialVersionUID = -2182747459195865750L;
static {
diff --git a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileImage.java b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileImage.java
index 99d2c1d..2879fc3 100644
--- a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileImage.java
+++ b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileImage.java
@@ -30,15 +30,18 @@
import tools.dynamia.zk.ComponentAliasIndex;
import tools.dynamia.zk.ImageCache;
+import java.io.Serial;
+
public class EntityFileImage extends Image {
- private static SimpleCache URL_CACHE = new SimpleCache<>();
- private static SimpleCache URL_THUMB_CACHE = new SimpleCache<>();
+ private static final SimpleCache URL_CACHE = new SimpleCache<>();
+ private static final SimpleCache URL_THUMB_CACHE = new SimpleCache<>();
/**
*
*/
+ @Serial
private static final long serialVersionUID = -2182747459195865750L;
static {
@@ -50,7 +53,7 @@ public class EntityFileImage extends Image {
private boolean thumbnail = false;
private int thumbnailHeight = 64;
private int thumbnailWidth = 64;
- private String noPhotoPath = "/zkau/web/tools/images/no-photo.jpg";
+ private String noPhotoPath = "/static/dynamia-tools/images/no-photo.jpg";
public EntityFile getValue() {
return entityFile;
diff --git a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileUploadlink.java b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileUploadlink.java
index 9f83c64..9bb7e89 100644
--- a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileUploadlink.java
+++ b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileUploadlink.java
@@ -29,12 +29,14 @@
import tools.dynamia.zk.ui.Uploadlink;
import java.io.File;
+import java.io.Serial;
public class EntityFileUploadlink extends Uploadlink {
/**
*
*/
+ @Serial
private static final long serialVersionUID = -2182747459195865750L;
static {
@@ -43,7 +45,7 @@ public class EntityFileUploadlink extends Uploadlink {
}
private EntityFile entityFile;
- private EntityFileService service = Containers.get().findObject(EntityFileService.class);
+ private final EntityFileService service = Containers.get().findObject(EntityFileService.class);
private boolean shared;
private String subfolder;
private String storedFileName;
diff --git a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/FilesCountImage.java b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/FilesCountImage.java
index 9d00974..5d7ab9c 100644
--- a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/FilesCountImage.java
+++ b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/FilesCountImage.java
@@ -25,11 +25,14 @@
import tools.dynamia.zk.ComponentAliasIndex;
import tools.dynamia.zk.util.ZKUtil;
+import java.io.Serial;
+
public class FilesCountImage extends A {
/**
*
*/
+ @Serial
private static final long serialVersionUID = 1L;
private IconSize iconSize = IconSize.SMALL;
private String icon = "attachment";
@@ -50,10 +53,9 @@ public FilesCountImage(int value) {
public void setValue(int value) {
try {
- int count = value;
- if (count > 0) {
+ if (value > 0) {
ZKUtil.configureComponentIcon(icon, this, iconSize);
- setTooltiptext(count + " archivos adjuntos");
+ setTooltiptext(value + " archivos adjuntos");
} else {
setImage(null);
getChildren().clear();
diff --git a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/StorageCombobox.java b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/StorageCombobox.java
index dc9d954..84cf28a 100644
--- a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/StorageCombobox.java
+++ b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/StorageCombobox.java
@@ -17,6 +17,7 @@
package tools.dynamia.modules.entityfile.ui.components;
+import java.io.Serial;
import java.util.Optional;
import org.zkoss.zul.Combobox;
@@ -33,6 +34,7 @@ public class StorageCombobox extends Combobox {
/**
*
*/
+ @Serial
private static final long serialVersionUID = 3507817129731334840L;
static {
diff --git a/sources/ui/src/main/resources/META-INF/descriptors/EntityFileConfig.yml b/sources/ui/src/main/resources/META-INF/descriptors/EntityFileConfig.yml
index 0b814c4..68518e2 100644
--- a/sources/ui/src/main/resources/META-INF/descriptors/EntityFileConfig.yml
+++ b/sources/ui/src/main/resources/META-INF/descriptors/EntityFileConfig.yml
@@ -39,10 +39,11 @@ fields:
params:
parameterName: AWS_S3_BUCKET
cacheable: true
- s3Endpoint:
- label: Endpoint
+ s3Region:
+ label: Region
params:
- parameterName: AWS_S3_ENDPOINT
+ parameterName: AWS_S3_REGION
+ defaultValue: us-east-1
cacheable: true
s3User:
label: Identity
@@ -58,7 +59,7 @@ fields:
groups:
s3:
label: Amazon Web Service (S3)
- fields: [ s3BucketName,s3Endpoint,s3User,s3Secret ]
+ fields: [ s3BucketName,s3Region,s3User,s3Secret ]
layout:
columns: 4
\ No newline at end of file