diff --git a/CHANGELOG.md b/CHANGELOG.md index b234634..72d64c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ ## [Unreleased] +### Added ✔️ +- The `TemporalFileManager` has been created to manage temporary files per request. + +* **OSdmsService:** Added `getTemporalFiles` method has been added to `OSdmsService`. + + ### Fixed 🐛 - Closed `S3ObjectInputStream` instances properly to avoid `CLOSE_WAIT` socket issues and potential memory/resource leaks during file download operations. diff --git a/ontimize-jee-sdms-common/pom.xml b/ontimize-jee-sdms-common/pom.xml index fbddfe1..f768e48 100644 --- a/ontimize-jee-sdms-common/pom.xml +++ b/ontimize-jee-sdms-common/pom.xml @@ -51,6 +51,11 @@ ontimize-jee-common + + jakarta.annotation + jakarta.annotation-api + + org.reflections diff --git a/ontimize-jee-sdms-common/src/main/java/com/ontimize/jee/sdms/common/action/IOSdmsAction.java b/ontimize-jee-sdms-common/src/main/java/com/ontimize/jee/sdms/common/action/IOSdmsAction.java index 7b84f12..648ef80 100644 --- a/ontimize-jee-sdms-common/src/main/java/com/ontimize/jee/sdms/common/action/IOSdmsAction.java +++ b/ontimize-jee-sdms-common/src/main/java/com/ontimize/jee/sdms/common/action/IOSdmsAction.java @@ -66,6 +66,8 @@ public interface IOSdmsAction { */ EntityResult download( OSdmsRestDataDto data ); + EntityResult getTemporalFiles( OSdmsRestDataDto data ); + // ------------------------------------------------------------------------------------------------------------------ \\ // -------| DMS - UPLOAD |------------------------------------------------------------------------------------------- \\ // ------------------------------------------------------------------------------------------------------------------ \\ diff --git a/ontimize-jee-sdms-common/src/main/java/com/ontimize/jee/sdms/common/file/DefaultTemporalFileManager.java b/ontimize-jee-sdms-common/src/main/java/com/ontimize/jee/sdms/common/file/DefaultTemporalFileManager.java new file mode 100644 index 0000000..4bd3c3a --- /dev/null +++ b/ontimize-jee-sdms-common/src/main/java/com/ontimize/jee/sdms/common/file/DefaultTemporalFileManager.java @@ -0,0 +1,56 @@ +package com.ontimize.jee.sdms.common.file; + +import jakarta.annotation.PreDestroy; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.context.annotation.RequestScope; + +import java.io.*; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@Component +@RequestScope +public class DefaultTemporalFileManager implements TemporalFileManager{ + + @Value( "${ontimize.sdms.file.temporal.directory}" ) + private String temporalDirectory; + + private final List files = new ArrayList<>(); + + @Override + public File create( final String name, final InputStream inputStream ) throws IOException { + final File directory = new File( this.temporalDirectory ); + final File file; + if( directory.exists() && directory.isDirectory() ) file = File.createTempFile( name, ".tmp", directory ); + else file = File.createTempFile( name, ".tmp" ); + try( FileOutputStream fos = new FileOutputStream( file)) { + inputStream.transferTo(fos); + } + this.files.add( file ); + return file; + } + + @Override + public File create( final InputStream inputStream ) throws IOException { + return this.create( UUID.randomUUID().toString(), inputStream ); + } + + @Override + public void delete( final File file ) { + this.files.stream().filter( target -> target.getAbsolutePath().equals( file.getAbsolutePath() ) ) + .findFirst() + .ifPresent( target -> { + this.files.remove( target ); + if( target.exists() ) target.delete(); + }); + } + + @PreDestroy + @Override + public void cleanUp() { + this.files.forEach( file -> { if( file.exists() ) file.delete(); }); + } +} diff --git a/ontimize-jee-sdms-common/src/main/java/com/ontimize/jee/sdms/common/file/TemporalFileManager.java b/ontimize-jee-sdms-common/src/main/java/com/ontimize/jee/sdms/common/file/TemporalFileManager.java new file mode 100644 index 0000000..d2d0239 --- /dev/null +++ b/ontimize-jee-sdms-common/src/main/java/com/ontimize/jee/sdms/common/file/TemporalFileManager.java @@ -0,0 +1,13 @@ +package com.ontimize.jee.sdms.common.file; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +public interface TemporalFileManager { + + File create( InputStream inputStream ) throws IOException; + File create( String name, InputStream inputStream ) throws IOException; + void delete( File file ); + void cleanUp(); +} diff --git a/ontimize-jee-sdms-common/src/main/java/com/ontimize/jee/sdms/common/zip/OSdmsZipCompressor.java b/ontimize-jee-sdms-common/src/main/java/com/ontimize/jee/sdms/common/zip/OSdmsZipCompressor.java index 2d1ddd0..c97af1d 100644 --- a/ontimize-jee-sdms-common/src/main/java/com/ontimize/jee/sdms/common/zip/OSdmsZipCompressor.java +++ b/ontimize-jee-sdms-common/src/main/java/com/ontimize/jee/sdms/common/zip/OSdmsZipCompressor.java @@ -4,10 +4,7 @@ import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; import java.util.List; import java.util.Objects; import java.util.Set; @@ -36,6 +33,7 @@ public class OSdmsZipCompressor implements IOSdmsZipCompressor { @Override public OSdmsZipDto compress( final String zipName, final List dataToZip ) { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (ZipOutputStream zos = new ZipOutputStream(baos)) { final Set data = dataToZip.stream() .map(IOSdmsZippeable::getDataToZip) @@ -44,22 +42,30 @@ public OSdmsZipDto compress( final String zipName, f for (final OSdmsZipData zipData : data) { final ZipEntry entry = new ZipEntry(zipData.getFileName()); - try ( InputStream inputStream = new ByteArrayInputStream( zipData.getFileContent() )) { + final File file = zipData.getFile(); + + if (file == null || !file.exists()) { + LOGGER.warn("File {} does not exist or is null, skipping", zipData.getFileName()); + continue; + } + + try (InputStream inputStream = new FileInputStream(file)) { zos.putNextEntry(entry); - byte[] buffer = new byte[1024]; + byte[] buffer = new byte[4096]; int length; while ((length = inputStream.read(buffer)) >= 0) { zos.write(buffer, 0, length); } zos.closeEntry(); } catch (IOException e) { - LOGGER.error("Error compressing entry {}: {}", zipData.getFileName(), e.getMessage()); + LOGGER.error("Error compressing file {}: {}", zipData.getFileName(), e.getMessage()); } } } catch (IOException e) { LOGGER.error("Error creating ZIP output stream: {}", e.getMessage()); } + // Construir el DTO con el contenido del zip en memoria final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); final OSdmsZipDto zipDto = new OSdmsZipDto(); zipDto.setFile(bais); diff --git a/ontimize-jee-sdms-common/src/main/java/com/ontimize/jee/sdms/common/zip/OSdmsZipData.java b/ontimize-jee-sdms-common/src/main/java/com/ontimize/jee/sdms/common/zip/OSdmsZipData.java index b444962..f2402f2 100644 --- a/ontimize-jee-sdms-common/src/main/java/com/ontimize/jee/sdms/common/zip/OSdmsZipData.java +++ b/ontimize-jee-sdms-common/src/main/java/com/ontimize/jee/sdms/common/zip/OSdmsZipData.java @@ -1,5 +1,6 @@ package com.ontimize.jee.sdms.common.zip; +import java.io.File; import java.util.Objects; @@ -14,18 +15,18 @@ public class OSdmsZipData { private String fileName; /** - * The inputStream field represents the input stream to be zipped. + * The File field represents the file to be zipped. */ - private byte[] fileContent; + private File file; // ------------------------------------------------------------------------------------------------------------------ \\ public OSdmsZipData() { } - public OSdmsZipData( final String fileName, final byte[] fileContent ) { + public OSdmsZipData( final String fileName, final File file ) { this.setFileName( fileName ); - this.setFileContent( fileContent ); + this.setFile( file ); } // ------------------------------------------------------------------------------------------------------------------ \\ @@ -40,12 +41,12 @@ public void setFileName( final String fileName ) { this.fileName = fileName; } - public byte[] getFileContent() { - return this.fileContent; + public File getFile() { + return this.file; } - public void setFileContent( final byte[] content ) { - this.fileContent = content; + public void setFile( final File file ) { + this.file = file; } // ------------------------------------------------------------------------------------------------------------------ \\ diff --git a/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/main/java/com/ontimize/jee/sdms/engine/s3/OSdmsS3Engine.java b/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/main/java/com/ontimize/jee/sdms/engine/s3/OSdmsS3Engine.java index e266bf9..6bd23f2 100644 --- a/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/main/java/com/ontimize/jee/sdms/engine/s3/OSdmsS3Engine.java +++ b/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/main/java/com/ontimize/jee/sdms/engine/s3/OSdmsS3Engine.java @@ -69,6 +69,12 @@ public EntityResult download( final OSdmsRestDataDto data ) { return this.oSdmsCommandHandler.run( new OSdmsS3DownloadCommand( requestFilter ) ); } + @Override + public EntityResult getTemporalFiles( final OSdmsRestDataDto data ) { + final OSdmsS3InputFilter requestFilter = this.oSdmsS3InputFilterMapper.map( data ); + return this.oSdmsCommandHandler.run( new OSdmsS3GetTemporalFilesCommand( requestFilter ) ); + } + // ------------------------------------------------------------------------------------------------------------------ \\ // -------| DMS - UPLOAD |------------------------------------------------------------------------------------------- \\ // ------------------------------------------------------------------------------------------------------------------ \\ diff --git a/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/main/java/com/ontimize/jee/sdms/engine/s3/command/OSdmsS3DownloadCommand.java b/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/main/java/com/ontimize/jee/sdms/engine/s3/command/OSdmsS3DownloadCommand.java index c48e260..1ce1be1 100644 --- a/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/main/java/com/ontimize/jee/sdms/engine/s3/command/OSdmsS3DownloadCommand.java +++ b/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/main/java/com/ontimize/jee/sdms/engine/s3/command/OSdmsS3DownloadCommand.java @@ -27,7 +27,7 @@ /** * Command to download files from S3 */ -public class OSdmsS3DownloadCommand implements IOSdmsCommand { +public class OSdmsS3DownloadCommand implements IOSdmsCommand { //Constants private static final String ZIP_NAME = "data.zip"; diff --git a/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/main/java/com/ontimize/jee/sdms/engine/s3/command/OSdmsS3GetTemporalFilesCommand.java b/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/main/java/com/ontimize/jee/sdms/engine/s3/command/OSdmsS3GetTemporalFilesCommand.java new file mode 100644 index 0000000..f32bcf2 --- /dev/null +++ b/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/main/java/com/ontimize/jee/sdms/engine/s3/command/OSdmsS3GetTemporalFilesCommand.java @@ -0,0 +1,163 @@ +package com.ontimize.jee.sdms.engine.s3.command; + +import com.amazonaws.services.s3.model.ListObjectsRequest; +import com.ontimize.jee.common.dto.EntityResult; +import com.ontimize.jee.sdms.common.command.IOSdmsCommand; +import com.ontimize.jee.sdms.common.inyector.IOSdmsInyector; +import com.ontimize.jee.sdms.common.response.builder.IOSdmsResponseBuilder; +import com.ontimize.jee.sdms.common.workspace.manager.IOSdmsWorkspaceManager; +import com.ontimize.jee.sdms.common.zip.IOSdmsZipCompressor; +import com.ontimize.jee.sdms.common.zip.OSdmsZipDto; +import com.ontimize.jee.sdms.engine.s3.repository.IOSdmsS3Repository; +import com.ontimize.jee.sdms.engine.s3.repository.OSdmsS3RepositoryProxy; +import com.ontimize.jee.sdms.engine.s3.repository.dto.OSdmsS3RepositoryDto; +import com.ontimize.jee.sdms.engine.s3.repository.response.OSdmsS3RepositoryResponse; +import com.ontimize.jee.sdms.engine.s3.repository.response.codes.OSdmsS3RepositoryResponseCodes; +import com.ontimize.jee.sdms.engine.s3.util.config.IOSdmsS3EngineConfig; +import com.ontimize.jee.sdms.engine.s3.util.input.filter.OSdmsS3InputFilter; +import com.ontimize.jee.sdms.engine.s3.util.input.filter.reader.IOSdmsS3FilterReader; +import com.ontimize.jee.sdms.engine.s3.util.normalize.IOSdmsS3KeyNormalize; +import com.ontimize.jee.sdms.engine.s3.util.response.mapper.IOSdmsS3ResponseMapper; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + + +/** + * Command to download files from S3 + */ +public class OSdmsS3GetTemporalFilesCommand implements IOSdmsCommand { + + + //Messages + private static final String MESSAGE_ERROR_NO_ACTIVE_WORKSPACE = "No active workspace found"; + private static final String MESSAGE_ERROR_NO_BUCKET = "No S3 bucket has been configured"; + private static final String MESSAGE_NO_CONTENT = "No file has been obtained from the query"; + + + // Dependencies + private IOSdmsS3Repository repository; + private IOSdmsResponseBuilder responseBuilder; + private IOSdmsS3ResponseMapper responseMapper; + private IOSdmsWorkspaceManager workspaceManager; + + + //Data + private String bucket; + private OSdmsS3InputFilter filter; + private List queries = new ArrayList<>(); + + + //Respone + private OSdmsS3RepositoryResponse response; + +// ------------------------------------------------------------------------------------------------------------------ \\ +// ------| ENTRYPOINT |---------------------------------------------------------------------------------------------- \\ +// ------------------------------------------------------------------------------------------------------------------ \\ + + public OSdmsS3GetTemporalFilesCommand( final OSdmsS3InputFilter filter ) { + this.filter = filter; + } + +// ------------------------------------------------------------------------------------------------------------------ \\ +// ------| INIT |--------------------------------------------------------------------------------------------------- \\ +// ------------------------------------------------------------------------------------------------------------------ \\ + + @Override + public void init( final IOSdmsInyector inyector ) { + //Inyect dependencies + this.repository = inyector.get( OSdmsS3RepositoryProxy.class ); + this.responseBuilder = inyector.get( IOSdmsResponseBuilder.class ); + this.responseMapper = inyector.get( IOSdmsS3ResponseMapper.class ); + this.workspaceManager = inyector.get( IOSdmsWorkspaceManager.class ); + final IOSdmsS3FilterReader filterParamReader = inyector.get( IOSdmsS3FilterReader.class ); + final IOSdmsS3EngineConfig s3EngineConfig = inyector.get( IOSdmsS3EngineConfig.class ); + final IOSdmsS3KeyNormalize keyNormalize = inyector.get( IOSdmsS3KeyNormalize.class ); + + //Get Data + this.workspaceManager.active( this.filter.getWorkspace(), this.filter.getData() ); + this.bucket = s3EngineConfig.getBucket(); + this.queries = filterParamReader.readAllKeys( this.filter ); + this.queries = this.queries.stream().map( keyNormalize::normalize ).collect( Collectors.toList() ); + } + +// ------------------------------------------------------------------------------------------------------------------ \\ +// ------| VALIDATE |------------------------------------------------------------------------------------------------ \\ +// ------------------------------------------------------------------------------------------------------------------ \\ + + @Override + public EntityResult validate() { + if( this.workspaceManager.getActive() == null ) { + return this.responseBuilder + .code( EntityResult.OPERATION_WRONG ) + .message( MESSAGE_ERROR_NO_ACTIVE_WORKSPACE ) + .build(); + } + + if( this.bucket == null ) { + return this.responseBuilder + .code( EntityResult.OPERATION_WRONG ) + .message( MESSAGE_ERROR_NO_BUCKET ) + .build(); + } + + return null; + } + +// ------------------------------------------------------------------------------------------------------------------ \\ +// ------| RUN |----------------------------------------------------------------------------------------------------- \\ +// ------------------------------------------------------------------------------------------------------------------ \\ + + @Override + public void run() { + final List requests = new ArrayList<>(); + + this.queries.forEach( prefix -> { + final ListObjectsRequest request = new ListObjectsRequest() + .withBucketName( this.bucket ) + .withPrefix( prefix ); + + if( this.filter.hasMaxKeys() ) request.withMaxKeys( this.filter.getMaxKeys() ); + if( this.filter.hasDelimiter() ) request.withDelimiter( this.filter.getDelimiter() ); + if( this.filter.hasMarker() ) request.withMarker( this.filter.getMarker() ); + + requests.add( request ); + } ); + + this.response = this.repository.download( requests ); + } + +// ------------------------------------------------------------------------------------------------------------------ \\ +// ------| RESPONSE |------------------------------------------------------------------------------------------------ \\ +// ------------------------------------------------------------------------------------------------------------------ \\ + + @Override + public EntityResult response() { + EntityResult result = null; + + if( this.response != null ) { + final OSdmsS3RepositoryResponseCodes code = this.response.getCode(); + if( code == OSdmsS3RepositoryResponseCodes.OK ) { + result = this.responseBuilder + .code( EntityResult.OPERATION_SUCCESSFUL ) + .message( MESSAGE_NO_CONTENT ) + .build(); + + List data = this.response.getData().stream() + .filter( target -> ! target.getName().equals( OSdmsS3RepositoryDto.FILE_NAME_MARK_FOLDER ) ) + .collect( Collectors.toList() ); + this.response.setData( data ); + + if( data != null && !data.isEmpty() ) result = this.responseMapper.map( this.response ); + } + } + + if( result == null ) result = this.responseMapper.map( this.response ); + + return result; + } + +// ------------------------------------------------------------------------------------------------------------------ \\ + +} diff --git a/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/main/java/com/ontimize/jee/sdms/engine/s3/repository/OSdmsS3Repository.java b/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/main/java/com/ontimize/jee/sdms/engine/s3/repository/OSdmsS3Repository.java index 029391e..91b95ce 100644 --- a/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/main/java/com/ontimize/jee/sdms/engine/s3/repository/OSdmsS3Repository.java +++ b/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/main/java/com/ontimize/jee/sdms/engine/s3/repository/OSdmsS3Repository.java @@ -5,6 +5,7 @@ import com.amazonaws.services.s3.transfer.TransferManager; import com.amazonaws.services.s3.transfer.TransferManagerBuilder; import com.amazonaws.services.s3.transfer.Upload; +import com.ontimize.jee.sdms.common.file.TemporalFileManager; import com.ontimize.jee.sdms.engine.s3.repository.dto.OSdmsS3RepositoryDto; import com.ontimize.jee.sdms.engine.s3.repository.response.OSdmsS3RepositoryResponse; import com.ontimize.jee.sdms.engine.s3.repository.response.builder.IOSdmsS3RepositoryResponseBuilder; @@ -54,6 +55,7 @@ public class OSdmsS3Repository implements IOSdmsS3Repository { /** The s3 repository response builder to build the response of each operation. */ private @Autowired IOSdmsS3RepositoryResponseBuilder oSdmsS3RepositoryResponseBuilder; + private @Autowired TemporalFileManager temporalFileManager; // ------------------------------------------------------------------------------------------------------------------ \\ // -------| FIND |--------------------------------------------------------------------------------------------------- \\ @@ -77,7 +79,7 @@ public OSdmsS3RepositoryResponse find( final ListObjectsRe final ObjectMetadata objectMetadata = this.amazonS3.getObjectMetadata( target.getBucketName(), target.getKey() ); - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); dto.set( target ); dto.set( objectMetadata ); return dto; @@ -88,7 +90,7 @@ public OSdmsS3RepositoryResponse find( final ListObjectsRe final List commonPrefixes = requestResult.getCommonPrefixes(); if( commonPrefixes != null && ! commonPrefixes.isEmpty() ) { final List folders = commonPrefixes.stream().map( target -> { - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); dto.setFolderData( request.getBucketName(), target ); return dto; } ).collect( Collectors.toList() ); @@ -146,7 +148,7 @@ public OSdmsS3RepositoryResponse download( final ListObjec final GetObjectRequest getObjectRequest = new GetObjectRequest( target.getBucket(), target.getKey() ); try( final S3Object s3Object = this.amazonS3.getObject( getObjectRequest )){ if( s3Object != null ) { - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); dto.set( s3Object ); data.add( dto ); } diff --git a/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/main/java/com/ontimize/jee/sdms/engine/s3/repository/dto/OSdmsS3RepositoryDto.java b/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/main/java/com/ontimize/jee/sdms/engine/s3/repository/dto/OSdmsS3RepositoryDto.java index 90ab80e..bbd4326 100644 --- a/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/main/java/com/ontimize/jee/sdms/engine/s3/repository/dto/OSdmsS3RepositoryDto.java +++ b/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/main/java/com/ontimize/jee/sdms/engine/s3/repository/dto/OSdmsS3RepositoryDto.java @@ -4,10 +4,12 @@ import com.amazonaws.services.s3.model.Owner; import com.amazonaws.services.s3.model.S3Object; import com.amazonaws.services.s3.model.S3ObjectSummary; +import com.ontimize.jee.sdms.common.file.TemporalFileManager; import com.ontimize.jee.sdms.common.response.builder.IOSdmsMappeable; import com.ontimize.jee.sdms.common.zip.IOSdmsZippeable; import com.ontimize.jee.sdms.common.zip.OSdmsZipData; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.time.LocalDateTime; @@ -31,6 +33,8 @@ public class OSdmsS3RepositoryDto implements IOSdmsMappeable, IOSdmsZippeable { /** The name of the file that marks a folder in S3 */ public static final String FILE_NAME_MARK_FOLDER = ".ontimizeSdmsFolder"; + private final TemporalFileManager temporalFileManager; + /** The bucket name of S3 */ private String bucket; @@ -66,15 +70,17 @@ public class OSdmsS3RepositoryDto implements IOSdmsMappeable, IOSdmsZippeable { /** The metadata of S3 object */ private Map metadata; - /** The bytes of S3 file */ - private byte[] file; + /** The Temporal File of S3 file */ + private File file; // ------------------------------------------------------------------------------------------------------------------ \\ - public OSdmsS3RepositoryDto() { + public OSdmsS3RepositoryDto(final TemporalFileManager temporalFileManager ) { + this.temporalFileManager = temporalFileManager; } - public OSdmsS3RepositoryDto( final S3Object s3Object, final S3ObjectSummary s3ObjectSummary, final ObjectMetadata objectMetadata ) { + public OSdmsS3RepositoryDto( final TemporalFileManager temporalFileManager, final S3Object s3Object, final S3ObjectSummary s3ObjectSummary, final ObjectMetadata objectMetadata ) { + this.temporalFileManager = temporalFileManager; this.set( s3Object ); this.set( s3ObjectSummary ); this.set( objectMetadata ); @@ -186,11 +192,11 @@ public void setMetadata( final Map metadata ) { this.metadata = metadata; } - public byte[] getFile() { + public File getFile() { return this.file; } - public void setFile( final byte[] file ) { + public void setFile( final File file ) { this.file = file; } @@ -209,8 +215,8 @@ public void set( final S3Object s3Object ) { this.processKey( s3Object.getKey() ); this.bucket = s3Object.getBucketName(); try (final InputStream is = s3Object.getObjectContent()) { - this.file = is.readAllBytes(); - if( this.file != null ) this.size = (long) this.file.length; + this.file = this.temporalFileManager.create( this.key, is ); + if( this.file != null ) this.size = this.file.length(); } catch ( IOException e) { this.file = null; } @@ -358,7 +364,7 @@ public OSdmsZipData getDataToZip() { String fileName = sanitizedKey.replace( "/", "_" ); if( fileName.endsWith( "_" ) ) fileName = fileName.substring( 0, fileName.length() - 1 ); result = new OSdmsZipData(); - result.setFileContent( this.file ); + result.setFile( this.file ); result.setFileName( fileName ); } return result; diff --git a/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/test/java/com/ontimize/jee/sdms/engine/s3/repository/dto/OSdmsS3RepositoryDtoTest.java b/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/test/java/com/ontimize/jee/sdms/engine/s3/repository/dto/OSdmsS3RepositoryDtoTest.java index cfb348a..5d960eb 100644 --- a/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/test/java/com/ontimize/jee/sdms/engine/s3/repository/dto/OSdmsS3RepositoryDtoTest.java +++ b/ontimize-jee-sdms-engine/ontimize-jee-sdms-engine-s3/src/test/java/com/ontimize/jee/sdms/engine/s3/repository/dto/OSdmsS3RepositoryDtoTest.java @@ -2,16 +2,19 @@ import com.amazonaws.services.s3.model.*; +import com.ontimize.jee.sdms.common.file.TemporalFileManager; import com.ontimize.jee.sdms.common.zip.OSdmsZipData; import org.apache.http.client.methods.HttpRequestBase; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import org.mockito.Mockito; import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; import java.io.InputStream; -import java.net.HttpURLConnection; import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.*; @@ -20,7 +23,14 @@ import static org.mockito.Mockito.*; class OSdmsS3RepositoryDtoTest { + private TemporalFileManager temporalFileManager; + @BeforeEach + void setUp() throws IOException { + this.temporalFileManager = mock( TemporalFileManager.class ); + when( this.temporalFileManager.create( any( InputStream.class )) ).thenReturn( new File( "temp.txt" ) ); + when( this.temporalFileManager.create( any( String.class ), any( InputStream.class )) ).thenReturn( new File( "temp.txt" ) ); + } // ------------------------------------------------------------------------------------------------------------------ \\ // --------| SET (S3Object) |---------------------------------------------------------------------------------------- \\ @@ -37,7 +47,7 @@ void givenAValidS3Object_whenSetS3Object_thenDataIsSet( final String givenKey, f final SimpleDateFormat formatDate = new SimpleDateFormat( "dd/MM/yyyy-HH:mm:ss" ); //Given - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); final String givenBucket = "bucket"; final Long givenSize = 1L; final String givenCreationDate = "27/06/2023-10:30:20"; @@ -66,7 +76,7 @@ void givenAValidS3Object_whenSetS3Object_thenDataIsSet( final String givenKey, f final String key = dto.getKey(); final String prefix = dto.getPrefix(); final String name = dto.getName(); - final byte[] file = dto.getFile(); + final File file = dto.getFile(); final Date creationDate = dto.getCreationDate(); final Long size = dto.getSize(); final Map metadata = dto.getMetadata(); @@ -107,7 +117,7 @@ void givenAValidS3Object_whenSetS3Object_thenDataIsSet( final String givenKey, f }) void givenAValidS3ObjectSummary_whenSetS3ObjectSummary_thenDataIsSet( final String givenKey, final String expectedPrefix, final String expectedName ){ //Given - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); final String givenBucket = "bucket"; final Long givenSize = 1L; final Date givenLastModified = new Date(); @@ -169,7 +179,7 @@ void givenAValidS3ObjectMetadata_whenSetS3ObjectMetadata_thenDataIsSet(){ final SimpleDateFormat formatDate = new SimpleDateFormat( "dd/MM/yyyy-HH:mm:ss" ); //Given - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); final Long givenSize = 1L; final String givenCreationDate = "27/06/2023-10:30:20"; @@ -228,7 +238,7 @@ void givenAValidS3ObjectMetadata_whenSetS3ObjectMetadata_thenDataIsSet(){ void givenAValidFolderKey_whenSetFolderData_thenFolderDataIsSet( final String givenKey, final String expectedPrefix, final String expectedName ) { //Given final String givenBucket = "bucket"; - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); //When dto.setFolderData( givenBucket, givenKey ); @@ -281,7 +291,7 @@ void givenAValidFolderKey_whenSetFolderData_thenFolderDataIsSet( final String gi void givenAValidKeyAndSpecificWorkspaces_whenSetRelativeKey_thenRelativeKeyIsSet( final String givenKey, final String expectedRelativeKey ) { //Given final List givenWorkspaces = Arrays.asList( "entity/1", "entity/5", "entity/10", "entity/50", "entity/images/top" ); - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); dto.setKey( givenKey ); //When @@ -314,7 +324,7 @@ void givenAValidKeyAndSpecificWorkspaces_whenSetRelativeKey_thenRelativeKeyIsSet void givenAValidKeyAndSpecificWorkspaces_whenSetRelativePrefix_thenRelativePrefixIsSet( final String givenPrefix, final String expectedRelativePrefix ) { //Given final List givenWorkspaces = Arrays.asList( "entity/1", "entity/5", "entity/10", "entity/50", "entity/images/top" ); - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); dto.setPrefix( givenPrefix ); //When @@ -380,7 +390,7 @@ void givenOSdmsS3RepositoryDto_whenCallToMap_thenBuildACorrectMap() { when( givenS3Object.getObjectMetadata() ).thenReturn( givenObjectMetadata ); //Set Data in DTO - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); dto.set( givenS3ObjectSummary ); dto.set( givenS3Object ); dto.setRelativeKey( givenWorkspaces ); @@ -419,14 +429,13 @@ void givenOSdmsS3RepositoryDto_whenCallGetDataToZip_thenOSdmsZipData() { final String givenKey = "/entity/1/proof.txt"; final String givenName = "proof.txt"; final boolean givenFolder = false; - final byte[] givenFileBytes = "contenido de prueba".getBytes( StandardCharsets.UTF_8 ); //Set Data in DTO - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); dto.setKey( givenKey ); dto.setName( givenName ); dto.setFolder( givenFolder ); - dto.setFile( givenFileBytes ); + dto.setFile( new File( givenName )); //When final OSdmsZipData result = dto.getDataToZip(); @@ -434,8 +443,8 @@ void givenOSdmsS3RepositoryDto_whenCallGetDataToZip_thenOSdmsZipData() { //Then assertNotNull( result, () -> "The result should not be null" ); - final byte[] fileContent = result.getFileContent(); - assertNotNull( fileContent, () -> "The File Content should not be null" ); + final File file = result.getFile(); + assertNotNull( file, () -> "The File should not be null" ); final String fileName = result.getFileName(); assertEquals( expectedFileName, fileName, () -> "Unexpected fileName" ); @@ -476,7 +485,7 @@ void givenS3Data_whenCallConstructor_thenCreateNewInstanceWithSameData(){ when( givenS3ObjectSummary.getOwner().getDisplayName() ).thenReturn( givenOwnerDisplayName ); //When - final OSdmsS3RepositoryDto result = new OSdmsS3RepositoryDto( givenS3Object, givenS3ObjectSummary, givenObjectMetadata ); + final OSdmsS3RepositoryDto result = new OSdmsS3RepositoryDto( this.temporalFileManager, givenS3Object, givenS3ObjectSummary, givenObjectMetadata ); //Then assertNotNull( result, () -> "The result should not be null" ); @@ -493,7 +502,7 @@ void givenS3Data_whenCallConstructor_thenCreateNewInstanceWithSameData(){ @Test void givenBucketNameAsString_whenCallSetBucket_thenCheckTheNewValueWithCallGetter(){ //Given - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); final String givenBucketName = "bucket"; //When @@ -509,7 +518,7 @@ void givenBucketNameAsString_whenCallSetBucket_thenCheckTheNewValueWithCallGette @Test void givenKeyAsString_whenCallSetKey_thenCheckTheNewValueWithCallGetter(){ //Given - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); final String givenKey = "key"; //When @@ -525,7 +534,7 @@ void givenKeyAsString_whenCallSetKey_thenCheckTheNewValueWithCallGetter(){ @Test void givenRelativeKeyAsString_whenCallSetRelativeKey_thenCheckTheNewValueWithCallGetter(){ //Given - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); final String givenRelativeKey = "relativeKey"; //When @@ -541,7 +550,7 @@ void givenRelativeKeyAsString_whenCallSetRelativeKey_thenCheckTheNewValueWithCal @Test void givenRelativePrefixAsString_whenCallSetRelativePrefix_thenCheckTheNewValueWithCallGetter(){ //Given - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); final String givenRelativePrefix = "relativePrefix"; //When @@ -557,7 +566,7 @@ void givenRelativePrefixAsString_whenCallSetRelativePrefix_thenCheckTheNewValueW @Test void givenPrefixAsString_whenCallSetPrefix_thenCheckTheNewValueWithCallGetter(){ //Given - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); final String givenPrefix = "prefix"; //When @@ -573,7 +582,7 @@ void givenPrefixAsString_whenCallSetPrefix_thenCheckTheNewValueWithCallGetter(){ @Test void givenNameAsString_whenCallSetName_thenCheckTheNewValueWithCallGetter(){ //Given - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); final String givenName = "name"; //When @@ -589,7 +598,7 @@ void givenNameAsString_whenCallSetName_thenCheckTheNewValueWithCallGetter(){ @Test void givenOwnerAsString_whenCallSetOwner_thenCheckTheNewValueWithCallGetter(){ //Given - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); final String givenOwner = "owner"; //When @@ -605,7 +614,7 @@ void givenOwnerAsString_whenCallSetOwner_thenCheckTheNewValueWithCallGetter(){ @Test void givenSizeAsLong_whenCallSetSize_thenCheckTheNewValueWithCallGetter(){ //Given - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); final Long givenSize = 1L; //When @@ -621,7 +630,7 @@ void givenSizeAsLong_whenCallSetSize_thenCheckTheNewValueWithCallGetter(){ @Test void givenFolderFlagAsBoolean_whenCallSetFolder_thenCheckTheNewValueWithCallGetter(){ //Given - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); final boolean givenFolderFlag = true; //When @@ -637,7 +646,7 @@ void givenFolderFlagAsBoolean_whenCallSetFolder_thenCheckTheNewValueWithCallGett void givenCreationDateAsDate_whenCallSetCreationDate_thenCheckTheNewValueWithCallGetter() { //Given final Date givenCreationDate = new Date(); - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); //When dto.setCreationDate( givenCreationDate ); @@ -654,7 +663,7 @@ void givenCreationDateAsString_whenCallSetCreationDate_thenCheckTheNewValueWithC //Given final String givenCreationDate = "27/06/2023-10:30:20"; - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); //When dto.setCreationDate( givenCreationDate ); @@ -670,7 +679,7 @@ void givenCreationDateAsString_whenCallSetCreationDate_thenCheckTheNewValueWithC void givenLastModifiedAsDate_whenCallSetLastModified_thenCheckTheNewValueWithCallGetter() { //Given final Date givenLastModified = new Date(); - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); //When dto.setLastModified( givenLastModified ); @@ -689,7 +698,7 @@ void givenMetadadataAsMap_whenCallSetMetadata_thenCheckTheNewValueWithCallGetter final Map givenMetadata = Mockito.mock( Map.class ); when( givenMetadata.size() ).thenReturn( expectedSize ); - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); //When dto.setMetadata( givenMetadata ); @@ -705,14 +714,13 @@ void givenMetadadataAsMap_whenCallSetMetadata_thenCheckTheNewValueWithCallGetter @Test void givenFileAsBytes_whenCallSetFile_thenCheckTheNewValueWithCallGetter() { //Given - final byte[] givenFileBytes = "contenido de prueba".getBytes( StandardCharsets.UTF_8 ); - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(this.temporalFileManager ); //When - dto.setFile( givenFileBytes ); + dto.setFile( new File( "proof.tmp" ) ); //Then - final byte[] result = dto.getFile(); + final File result = dto.getFile(); assertNotNull( result, () -> "The result should not be null" ); } @@ -726,14 +734,13 @@ void givenOSdmsS3RepositoryDto_whenCallToString_thenCorrectStringRepresentation( final String givenKey = "/entity/1/proof.txt"; final String givenName = "proof.txt"; final boolean givenFolder = false; - final byte[] givenFileBytes = "contenido de prueba".getBytes( StandardCharsets.UTF_8 ); //Set Data in DTO - final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto(); + final OSdmsS3RepositoryDto dto = new OSdmsS3RepositoryDto( this.temporalFileManager ); dto.setKey( givenKey ); dto.setName( givenName ); dto.setFolder( givenFolder ); - dto.setFile( givenFileBytes ); + dto.setFile( new File( givenName )); //When final String result = dto.toString(); diff --git a/ontimize-jee-sdms-server/src/main/java/com/ontimize/jee/sdms/server/service/OSdmsService.java b/ontimize-jee-sdms-server/src/main/java/com/ontimize/jee/sdms/server/service/OSdmsService.java index 7a48e74..4524909 100644 --- a/ontimize-jee-sdms-server/src/main/java/com/ontimize/jee/sdms/server/service/OSdmsService.java +++ b/ontimize-jee-sdms-server/src/main/java/com/ontimize/jee/sdms/server/service/OSdmsService.java @@ -66,7 +66,12 @@ public EntityResult download( final OSdmsRestDataDto data ) { return this.engine.download( data ); } -// ------------------------------------------------------------------------------------------------------------------ \\ + @Override + public EntityResult getTemporalFiles( final OSdmsRestDataDto data ) { + return this.engine.getTemporalFiles( data ); + } + + // ------------------------------------------------------------------------------------------------------------------ \\ // -------| DMS - UPLOAD |------------------------------------------------------------------------------------------- \\ // ------------------------------------------------------------------------------------------------------------------ \\ diff --git a/pom.xml b/pom.xml index 4e16a70..dfa04c8 100644 --- a/pom.xml +++ b/pom.xml @@ -146,6 +146,12 @@ ${ontimize-jee.version} + + jakarta.annotation + jakarta.annotation-api + 2.1.1 + + org.reflections