From dbb9ffaf18f2d6f6c56d142e302151f03190cf79 Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 14 Sep 2024 20:08:03 -0600 Subject: [PATCH] replacing log4j with slf4j api. code cleanup and improvements. documentation improvements. --- build.gradle | 5 +-- gradle.properties | 2 +- .../api/controller/ThumbnailController.java | 2 +- .../api/service/ThumbnailService.java | 2 +- .../makbn/jthumbnail/core/JThumbnailer.java | 28 +++++++----- .../jthumbnail/core/ThumbnailerManager.java | 31 ++++++------- .../core/config/ApplicationConfig.java | 10 ++--- .../config/OfficeManagerConfiguration.java | 6 +-- .../UnsupportedInputFileFormatException.java | 13 ------ .../core/model/ExecutionResult.java | 22 ++++----- .../core/model/ThumbnailCandidate.java | 45 ++++++------------- .../thumbnailers/JODConverterThumbnailer.java | 15 +++---- .../core/thumbnailers/MP3Thumbnailer.java | 8 ++-- .../core/thumbnailers/MPEGThumbnailer.java | 7 ++- .../thumbnailers/NativeImageThumbnailer.java | 17 +++---- .../thumbnailers/OpenOfficeThumbnailer.java | 39 ++++++++++------ .../core/thumbnailers/Thumbnailer.java | 6 +-- .../makbn/jthumbnail/core/util/IOUtil.java | 33 ++++++++++---- .../jthumbnail/core/util/ResizeImage.java | 16 +++---- .../core/util/mime/DocFileIdentifier.java | 6 +-- .../core/util/mime/MP3FileIdentifier.java | 8 ++-- .../core/util/mime/MPEGFileIdentifier.java | 8 ++-- .../core/util/mime/MimeTypeDetector.java | 14 +++--- .../util/mime/Office2007FileIdentifier.java | 9 ++-- .../core/util/mime/OfficeFileIdentifier.java | 15 +++---- .../core/util/mime/PptFileIdentifier.java | 1 - .../core/util/mime/XlsFileIdentifier.java | 5 ++- .../makbn/jthumbnail/ThumbnailerTest.java | 9 +++- 28 files changed, 183 insertions(+), 199 deletions(-) diff --git a/build.gradle b/build.gradle index ec2e015..35c9fda 100644 --- a/build.gradle +++ b/build.gradle @@ -42,8 +42,7 @@ dependencies { implementation "org.apache.poi:poi:${apachepoi_ver}" implementation "org.apache.poi:poi-scratchpad:${apachepoi_ver}" implementation "commons-io:commons-io:${commonsio_ver}" - implementation "org.apache.logging.log4j:log4j-api:${log4j_ver}" - implementation "org.apache.logging.log4j:log4j-core:${log4j_ver}" + implementation "org.slf4j:slf4j-api:${slf4j_ver}" implementation "org.jodconverter:jodconverter-local:${jod_ver}" implementation "org.apache.pdfbox:pdfbox:${pdfbox_ver}" implementation "org.bytedeco:javacv:${javacv_ver}" @@ -73,7 +72,7 @@ publishing { groupId = 'io.github.makbn' artifactId = 'jthumbnail' - version = '2.1.0' + version = '2.2.0' } } diff --git a/gradle.properties b/gradle.properties index bb627f9..1afae5a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ apachepoi_ver=5.2.2 commonsio_ver=2.11.0 jod_ver=4.4.2 pdfbox_ver=2.0.26 -log4j_ver=2.18.0 +slf4j_ver=2.0.16 javacv_ver=1.5.7 opencv_ver=4.5.5-1.5.7 thumb_ver=0.4.17 diff --git a/src/main/java/io/github/makbn/jthumbnail/api/controller/ThumbnailController.java b/src/main/java/io/github/makbn/jthumbnail/api/controller/ThumbnailController.java index e6f4e7a..fb0ebcd 100644 --- a/src/main/java/io/github/makbn/jthumbnail/api/controller/ThumbnailController.java +++ b/src/main/java/io/github/makbn/jthumbnail/api/controller/ThumbnailController.java @@ -209,7 +209,7 @@ public ResponseEntity> checkThumbnailStatus(@Param ) ) }) - public @ResponseBody ResponseEntity downloadThumbnail(@Parameter( + public ResponseEntity downloadThumbnail(@Parameter( name = "uid", description = "The unique ID of the thumbnail to download", required = true diff --git a/src/main/java/io/github/makbn/jthumbnail/api/service/ThumbnailService.java b/src/main/java/io/github/makbn/jthumbnail/api/service/ThumbnailService.java index a951120..5bcb61c 100644 --- a/src/main/java/io/github/makbn/jthumbnail/api/service/ThumbnailService.java +++ b/src/main/java/io/github/makbn/jthumbnail/api/service/ThumbnailService.java @@ -47,7 +47,7 @@ public String requestThumbnail(@NonNull MultipartFile multipartFile) throws IOEx File file = createTempFile(multipartFile); CompletableFuture completableFuture = new CompletableFuture<>(); String uid = UUID.randomUUID().toString(); - ThumbnailCandidate candidate = new ThumbnailCandidate(file, uid); + ThumbnailCandidate candidate = ThumbnailCandidate.of(file, uid); waitingMap.put(uid, completableFuture); temporaryFilesMap.put(uid, file); // after keeping the references, let's create the thumbnail diff --git a/src/main/java/io/github/makbn/jthumbnail/core/JThumbnailer.java b/src/main/java/io/github/makbn/jthumbnail/core/JThumbnailer.java index 6ee7137..1c408df 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/JThumbnailer.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/JThumbnailer.java @@ -10,14 +10,14 @@ import lombok.experimental.FieldDefaults; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; -import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.stereotype.Component; import java.io.Closeable; import java.io.File; -@Configuration +@Component @EnableAsync @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) public class JThumbnailer implements Closeable { @@ -32,21 +32,15 @@ public JThumbnailer(ThumbnailerManager manager, ApplicationEventPublisher events this.typeDetector = new MimeTypeDetector(); } - @Async("async_thread_pool_task_executor") + @Async("asyncThreadPoolTaskExecutor") public void run(ThumbnailCandidate candidate, ThumbnailListener listener) { - try { - candidate.setThumbExt(typeDetector.getOutputExt(candidate.getFile())); - File out = manager.createThumbnail(candidate.getFile(), candidate.getThumbExt()); - listener.onThumbnailReady(candidate.getUid(), out); - } catch (ThumbnailerRuntimeException | ThumbnailerException re) { - listener.onThumbnailFailed(candidate.getUid(), re.getMessage(), 500); - } + internalRun(candidate, listener); } - @Async("async_thread_pool_task_executor") + @Async("asyncThreadPoolTaskExecutor") public void run(ThumbnailCandidate candidate) { - run(candidate, new ThumbnailListener() { + this.internalRun(candidate, new ThumbnailListener() { @Override public void onThumbnailReady(String hash, File thumbnail) { events.publishEvent(ThumbnailEvent.builder() @@ -67,6 +61,16 @@ public void onThumbnailFailed(String hash, String message, int code) { }); } + private void internalRun(ThumbnailCandidate candidate, ThumbnailListener listener) { + try { + candidate.setThumbExt(typeDetector.getOutputExt(candidate.getFile())); + File out = manager.createThumbnail(candidate.getFile(), candidate.getThumbExt()); + listener.onThumbnailReady(candidate.getUid(), out); + } catch (ThumbnailerRuntimeException | ThumbnailerException re) { + listener.onThumbnailFailed(candidate.getUid(), re.getMessage(), 500); + } + } + @Override public synchronized void close() { manager.close(); diff --git a/src/main/java/io/github/makbn/jthumbnail/core/ThumbnailerManager.java b/src/main/java/io/github/makbn/jthumbnail/core/ThumbnailerManager.java index b40c57b..76072ff 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/ThumbnailerManager.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/ThumbnailerManager.java @@ -5,7 +5,10 @@ import io.github.makbn.jthumbnail.core.model.ExecutionResult; import io.github.makbn.jthumbnail.core.thumbnailers.Thumbnailer; import io.github.makbn.jthumbnail.core.util.mime.MimeTypeDetector; -import lombok.extern.log4j.Log4j2; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; +import lombok.experimental.NonFinal; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FilenameUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.DependsOn; @@ -35,9 +38,10 @@ */ @Component @DependsOn({"DWGThumbnailer", "JODExcelThumbnailer", "PDFBoxThumbnailer", "MPEGThumbnailer", - "openOfficeThumbnailer", "jod_converter", "MP3Thumbnailer", "powerpointConverterThumbnailer", + "openOfficeThumbnailer", "jodConverter", "MP3Thumbnailer", "powerpointConverterThumbnailer", "JODHtmlConverterThumbnailer", "nativeImageThumbnailer", "textThumbnailer", "imageThumbnailer", "wordConverterThumbnailer"}) -@Log4j2 +@Slf4j +@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) public class ThumbnailerManager implements Thumbnailer { /** @@ -48,16 +52,17 @@ public class ThumbnailerManager implements Thumbnailer { /** * Magic Mime Detection ... a wrapper class to Aperature's Mime thingies. */ - private final MimeTypeDetector mimeTypeDetector; + MimeTypeDetector mimeTypeDetector; /** * Thumbnailers per MIME-Type they accept (ALL_MIME_WILDCARD for all) */ - private final Map> thumbnailers; + Map> thumbnailers; /** * Folder under which new thumbnails should be filed */ - private File thumbnailFolder; + @NonFinal + File thumbnailFolder; /** * Initialise Thumbnail Manager @@ -85,17 +90,7 @@ public File chooseThumbnailFilename(File input, String ext) throws ThumbnailerEx if (input == null) throw new IllegalArgumentException("Input file may not be null"); - File output; - - String name = FilenameUtils.getBaseName(input.getName()) + "_thumb"; - - name = name + "." + ext; - - - output = new File(thumbnailFolder, name); - - - return output; + return new File(thumbnailFolder, String.format("%s%s.%s", FilenameUtils.getBaseName(input.getName()), "_thumb", ext)); } /** @@ -182,7 +177,7 @@ public synchronized void close() { */ @Override public void generateThumbnail(File input, File output, String mimeType) throws ThumbnailerRuntimeException, ThumbnailerException { - if(!Files.exists(input.toPath())){ + if (!Files.exists(input.toPath())) { throw new ThumbnailerException("the input file does not exist"); } diff --git a/src/main/java/io/github/makbn/jthumbnail/core/config/ApplicationConfig.java b/src/main/java/io/github/makbn/jthumbnail/core/config/ApplicationConfig.java index 35b1261..40e341a 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/config/ApplicationConfig.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/config/ApplicationConfig.java @@ -3,7 +3,7 @@ import io.github.makbn.jthumbnail.core.thumbnailers.JODConverterThumbnailer; import io.github.makbn.jthumbnail.core.thumbnailers.JODHtmlConverterThumbnailer; import io.github.makbn.jthumbnail.core.thumbnailers.OpenOfficeThumbnailer; -import lombok.extern.log4j.Log4j2; +import lombok.extern.slf4j.Slf4j; import org.jodconverter.core.office.OfficeManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -11,8 +11,8 @@ import java.util.concurrent.Executor; -@Configuration("JTApplicationConfig") -@Log4j2 +@Configuration("jtApplicationConfig") +@Slf4j public class ApplicationConfig { @Bean @@ -20,13 +20,13 @@ public AppSettings getSettings() { return new AppSettings(); } - @Bean("jod_converter") + @Bean("jodConverter") public JODConverterThumbnailer getJodConverterThumbnailer(AppSettings settings, OpenOfficeThumbnailer openOfficeThumbnailer, OfficeManager manager) { log.debug("jod_converter bean created"); return new JODHtmlConverterThumbnailer(settings, openOfficeThumbnailer, manager); } - @Bean(name = "async_thread_pool_task_executor") + @Bean(name = "asyncThreadPoolTaskExecutor") public Executor threadPoolTaskExecutor(AppSettings settings) { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(settings.getAsyncCorePoolSize()); diff --git a/src/main/java/io/github/makbn/jthumbnail/core/config/OfficeManagerConfiguration.java b/src/main/java/io/github/makbn/jthumbnail/core/config/OfficeManagerConfiguration.java index 8e8b5a5..ec29f3d 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/config/OfficeManagerConfiguration.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/config/OfficeManagerConfiguration.java @@ -15,8 +15,8 @@ import java.io.File; import java.io.IOException; -@Configuration("JTOfficeManagerConfiguration") -@DependsOn("JTApplicationConfig") +@Configuration("jtOfficeManagerConfiguration") +@DependsOn("jtApplicationConfig") @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) public class OfficeManagerConfiguration { OfficeManager officeManager; @@ -43,7 +43,7 @@ public OfficeManagerConfiguration(AppSettings settings) throws IOException { } } - @Bean("office_manager") + @Bean("officeManager") public OfficeManager getOfficeManager() { return officeManager; } diff --git a/src/main/java/io/github/makbn/jthumbnail/core/exception/UnsupportedInputFileFormatException.java b/src/main/java/io/github/makbn/jthumbnail/core/exception/UnsupportedInputFileFormatException.java index 910f6d2..e14ada3 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/exception/UnsupportedInputFileFormatException.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/exception/UnsupportedInputFileFormatException.java @@ -3,20 +3,7 @@ import java.io.IOException; public class UnsupportedInputFileFormatException extends IOException { - - public UnsupportedInputFileFormatException() { - } - public UnsupportedInputFileFormatException(String arg0) { super(arg0); } - - public UnsupportedInputFileFormatException(Throwable arg0) { - super(arg0); - } - - public UnsupportedInputFileFormatException(String arg0, Throwable arg1) { - super(arg0, arg1); - } - } diff --git a/src/main/java/io/github/makbn/jthumbnail/core/model/ExecutionResult.java b/src/main/java/io/github/makbn/jthumbnail/core/model/ExecutionResult.java index dae00db..8ad4e6a 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/model/ExecutionResult.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/model/ExecutionResult.java @@ -1,20 +1,20 @@ package io.github.makbn.jthumbnail.core.model; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; +import lombok.experimental.NonFinal; @Data +@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) +@AllArgsConstructor +@RequiredArgsConstructor public class ExecutionResult { - private final boolean generated; - private Throwable exception; - - public ExecutionResult(boolean generated) { - this.generated = generated; - } - - public ExecutionResult(boolean generated, Throwable exception) { - this.generated = generated; - this.exception = exception; - } + boolean generated; + @NonFinal + Throwable exception; public static ExecutionResult success() { return new ExecutionResult(true); diff --git a/src/main/java/io/github/makbn/jthumbnail/core/model/ThumbnailCandidate.java b/src/main/java/io/github/makbn/jthumbnail/core/model/ThumbnailCandidate.java index 4ba9cd8..8d44ca2 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/model/ThumbnailCandidate.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/model/ThumbnailCandidate.java @@ -1,41 +1,22 @@ package io.github.makbn.jthumbnail.core.model; +import lombok.*; +import lombok.experimental.FieldDefaults; +import lombok.experimental.NonFinal; + import java.io.File; /** * @author Mehdi Akbarian-Rastaghi 2018-10-23 */ +@Data +@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) +@RequiredArgsConstructor(staticName = "of", access = AccessLevel.PUBLIC) public class ThumbnailCandidate { - private File file; - private String uid; - private String thumbExt; - - public ThumbnailCandidate(File file, String uid) { - this.file = file; - this.uid = uid; - } - - public File getFile() { - return file; - } - - public void setFile(File file) { - this.file = file; - } - - public String getThumbExt() { - return thumbExt; - } - - public void setThumbExt(String thumbExt) { - this.thumbExt = thumbExt; - } - - public String getUid() { - return uid; - } - - public void setUid(String uid) { - this.uid = uid; - } + @NonNull + File file; + @NonNull + String uid; + @NonFinal + String thumbExt; } diff --git a/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/JODConverterThumbnailer.java b/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/JODConverterThumbnailer.java index fb02670..287a195 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/JODConverterThumbnailer.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/JODConverterThumbnailer.java @@ -4,7 +4,7 @@ import io.github.makbn.jthumbnail.core.exception.ThumbnailerException; import io.github.makbn.jthumbnail.core.util.IOUtil; import io.github.makbn.jthumbnail.core.util.mime.MimeTypeDetector; -import lombok.extern.log4j.Log4j2; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FilenameUtils; import org.apache.tika.utils.SystemUtils; import org.jodconverter.core.DocumentConverter; @@ -20,9 +20,9 @@ import java.nio.file.Files; import java.nio.file.Path; -@Component("jod_converter") -@DependsOn("office_manager") -@Log4j2 +@Slf4j +@Component("jodConverter") +@DependsOn("officeManager") public abstract class JODConverterThumbnailer extends AbstractThumbnailer { /** @@ -88,8 +88,8 @@ public void generateThumbnail(File input, File output) throws ThumbnailerExcepti if (SystemUtils.IS_OS_WINDOWS) workingFile = new File(workingFile.getAbsolutePath().replace("\\\\", "\\")); - if(!officeManager.isRunning()){ - for (int i=0; i<10;i++){ + if (!officeManager.isRunning()) { + for (int i = 0; i < 10; i++) { Thread.sleep(1000); log.info("waiting for office manager"); if (officeManager.isRunning()) @@ -107,7 +107,6 @@ public void generateThumbnail(File input, File output) throws ThumbnailerExcepti .execute(); - if (outputTmp.length() == 0) { throw new ThumbnailerException("Could not convert into OpenOffice-File (file was empty)..."); } @@ -117,7 +116,7 @@ public void generateThumbnail(File input, File output) throws ThumbnailerExcepti } catch (IOException e) { throw new ThumbnailerException(e); } catch (OfficeException e) { - log.warn(e); + log.warn(e.getMessage(), e); throw new ThumbnailerException(e.getMessage()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); diff --git a/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/MP3Thumbnailer.java b/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/MP3Thumbnailer.java index d9e2f55..2d95254 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/MP3Thumbnailer.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/MP3Thumbnailer.java @@ -7,8 +7,7 @@ import com.mpatric.mp3agic.UnsupportedTagException; import io.github.makbn.jthumbnail.core.config.AppSettings; import io.github.makbn.jthumbnail.core.exception.ThumbnailerException; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -23,10 +22,9 @@ * created by Mehdi Akbarian-Rastaghi 2018-10-23 */ @Component +@Slf4j public class MP3Thumbnailer extends AbstractThumbnailer { - private static final Logger logger = LogManager.getLogger(MP3Thumbnailer.class); - @Autowired public MP3Thumbnailer(AppSettings appSettings) { super(appSettings); @@ -45,7 +43,7 @@ public void generateThumbnail(File input, File output) throws ThumbnailerExcepti } } catch (UnsupportedTagException | InvalidDataException | IOException e) { - logger.warn("MP3Thumbnailer", e); + log.warn("MP3Thumbnailer", e); throw new ThumbnailerException(); } diff --git a/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/MPEGThumbnailer.java b/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/MPEGThumbnailer.java index a2d8e77..8af2f01 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/MPEGThumbnailer.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/MPEGThumbnailer.java @@ -4,7 +4,7 @@ import io.github.makbn.jthumbnail.core.exception.ThumbnailerException; import io.github.makbn.jthumbnail.core.exception.ThumbnailerRuntimeException; import io.github.makbn.jthumbnail.core.util.GifSequenceWriter; -import lombok.extern.log4j.Log4j2; +import lombok.extern.slf4j.Slf4j; import org.bytedeco.javacv.FFmpegFrameGrabber; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -22,7 +22,7 @@ * created by Mehdi Akbarian-Rastaghi 2018-10-22 */ @Component -@Log4j2 +@Slf4j public class MPEGThumbnailer extends AbstractThumbnailer { @Autowired @@ -41,12 +41,11 @@ public void generateThumbnail(File input, File output) throws ThumbnailerExcepti /** * get thumbnail from multimedia files - * */ public void getThumb(String inputPath, String outputPath) throws IOException { - try( FFmpegFrameGrabber g = new FFmpegFrameGrabber(inputPath); + try (FFmpegFrameGrabber g = new FFmpegFrameGrabber(inputPath); ImageOutputStream output = new FileImageOutputStream(new File(outputPath))) { g.setFormat("mp4"); g.start(); diff --git a/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/NativeImageThumbnailer.java b/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/NativeImageThumbnailer.java index 9b3a216..7f9de3c 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/NativeImageThumbnailer.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/NativeImageThumbnailer.java @@ -4,8 +4,7 @@ import io.github.makbn.jthumbnail.core.config.AppSettings; import io.github.makbn.jthumbnail.core.exception.ThumbnailerException; import io.github.makbn.jthumbnail.core.util.ResizeImage; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -14,17 +13,15 @@ import java.io.IOException; /** - * This class uses Java Image I/O (Java's internal Image Processing library) in order to resize images. - * JAI can be extended with extra Readers, this Thumbnailer will use all available image readers. - *

- * Depends: - *

  • JAI Image I/O Tools (optional, for TIFF support) (@see http://java.net/projects/imageio-ext/ - licence not gpl compatible I suspect ...) + * This class generates image thumbnails using native Java libraries. + * This class extends the {@link AbstractThumbnailer} and overrides the methods + * to generate a thumbnail from an input image and to provide accepted MIME types. + * It utilizes the {@link ResizeImage} class to resize the images. */ +@Slf4j @Component public class NativeImageThumbnailer extends AbstractThumbnailer { - private static final Logger mLog = LogManager.getLogger("NativeImageThumbnailer"); - @Autowired public NativeImageThumbnailer(AppSettings appSettings) { super(appSettings); @@ -37,7 +34,7 @@ public void generateThumbnail(File input, File output) throws ThumbnailerExcepti resizer.setInputImage(input); resizer.writeOutput(output); } catch (IOException e) { - mLog.error(e); + log.error(e.getMessage(), e); throw new ThumbnailerException("File format could not be interpreted as image", e); } diff --git a/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/OpenOfficeThumbnailer.java b/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/OpenOfficeThumbnailer.java index 40f940b..ed7a878 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/OpenOfficeThumbnailer.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/OpenOfficeThumbnailer.java @@ -6,9 +6,8 @@ import io.github.makbn.jthumbnail.core.exception.ThumbnailerRuntimeException; import io.github.makbn.jthumbnail.core.util.IOUtil; import io.github.makbn.jthumbnail.core.util.ResizeImage; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FilenameUtils; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -20,24 +19,36 @@ import java.util.zip.ZipFile; /** - * This class extracts Thumbnails from OpenOffice-Files. - *

    - * Depends: - *

  • NOT on OpenOffice, as the Thumbnail is already inside the file. (184x256px regardless of page orientation) - * (So if the thumbnail generation is not correct, it's OpenOffice's fault, not our's :-) + * The OpenOfficeThumbnailer class is responsible for generating thumbnails for OpenOffice documents. + * It extends the AbstractThumbnailer class and can also handle PDF files by delegating to PDFBoxThumbnailer. + * If the file is not a PDF, it attempts to extract the thumbnail from an OpenOffice document, which is a zipped format. */ +@Slf4j @Component public class OpenOfficeThumbnailer extends AbstractThumbnailer { - - private static final Logger logger = LogManager.getLogger(OpenOfficeThumbnailer.class); private final PDFBoxThumbnailer pdfBoxThumbnailer; + /** + * Constructor that initializes the OpenOfficeThumbnailer with the necessary app settings and PDFBoxThumbnailer. + * + * @param appSettings Application settings used by the thumbnailer. + * @param pdfBoxThumbnailer An instance of PDFBoxThumbnailer for handling PDF files. + */ @Autowired public OpenOfficeThumbnailer(AppSettings appSettings, PDFBoxThumbnailer pdfBoxThumbnailer) { super(appSettings); this.pdfBoxThumbnailer = pdfBoxThumbnailer; } + /** + * Generates a thumbnail for the provided input file and saves it to the specified output location. + * If the input file is a PDF, the method delegates thumbnail generation to PDFBoxThumbnailer. + * For OpenOffice files, it attempts to extract an embedded thumbnail image. + * + * @param input The input file for which the thumbnail is to be generated. + * @param output The output file where the generated thumbnail will be saved. + * @throws ThumbnailerException If there are issues processing the file or extracting the thumbnail. + */ @Override public void generateThumbnail(File input, File output) throws ThumbnailerException { if (FilenameUtils.getExtension(input.getName()).equalsIgnoreCase("pdf")) { @@ -48,14 +59,14 @@ public void generateThumbnail(File input, File output) throws ThumbnailerExcepti try { zipFile = new ZipFile(input); } catch (ZipException e) { - logger.warn("OpenOfficeThumbnailer", e); + log.warn("OpenOfficeThumbnailer", e); throw new ThumbnailerException("This is not a zipped file. Is this really an OpenOffice file?", e); } catch (IOException e) { throw new ThumbnailerException(e); } ZipEntry entry = zipFile.getEntry("Thumbnails/thumbnail.png"); - try(BufferedInputStream in = new BufferedInputStream(zipFile.getInputStream(entry))) { + try (BufferedInputStream in = new BufferedInputStream(zipFile.getInputStream(entry))) { ResizeImage resizer = new ResizeImage(thumbWidth, thumbHeight); resizer.setInputImage(in); resizer.writeOutput(output); @@ -70,10 +81,10 @@ public void generateThumbnail(File input, File output) throws ThumbnailerExcepti } /** - * Get a List of accepted File Types. - * All OpenOffice Formats are accepted. + * Returns an array of MIME types that this thumbnailer accepts. + * It covers various OpenOffice document formats as well as PDFs and potential OpenOffice files in zip format. * - * @return MIME-Types + * @return An array of accepted MIME types. */ @Override public String[] getAcceptedMIMETypes() { diff --git a/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/Thumbnailer.java b/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/Thumbnailer.java index cfaf985..1dc08c9 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/Thumbnailer.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/thumbnailers/Thumbnailer.java @@ -37,10 +37,10 @@ public interface Thumbnailer extends Closeable { /** * This function will be called after all Thumbnails are generated. - * Note: This acts as a Deconstructor. Do not expect this object to work + * Note: This acts as a Deconstruct. Do not expect this object to work * after calling this method. * - * @throws IOException If some errors occured during finalising + * @throws IOException If some errors occurred during finalising */ void close() throws IOException; @@ -61,7 +61,7 @@ public interface Thumbnailer extends Closeable { /** * Get a list of all MIME Types that this Thumbnailer is ready to process. * - * @return List of MIME Types. If null, all Files may be passed to this Thumbnailer. + * @return Array of MIME Types. If null, all Files may be passed to this Thumbnailer. */ String[] getAcceptedMIMETypes(); } diff --git a/src/main/java/io/github/makbn/jthumbnail/core/util/IOUtil.java b/src/main/java/io/github/makbn/jthumbnail/core/util/IOUtil.java index b6912ed..08f74a3 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/util/IOUtil.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/util/IOUtil.java @@ -1,35 +1,50 @@ package io.github.makbn.jthumbnail.core.util; -import lombok.extern.log4j.Log4j2; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.util.zip.ZipFile; -@Log4j2 +/** + * Utility class for handling IO operations, such as closing resources or deleting files. + * This class provides methods to handle exceptions quietly without throwing them to the caller. + * It is designed for situations where the application can continue even if IO operations fail. + */ +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) public class IOUtil { - private IOUtil(){ - // do nothing - } - + /** + * Quietly closes the given {@link ZipFile}, suppressing any {@link IOException} that may occur. + * If an exception is thrown during the close operation, it is logged but not propagated. + * + * @param zipFile the {@link ZipFile} to be closed; can be null, in which case nothing happens. + */ public static void quietlyClose(ZipFile zipFile) { try { if (zipFile != null) zipFile.close(); } catch (IOException e) { - log.error(e); + log.error(e.getMessage(), e); } } + /** + * Quietly deletes the given {@link File}, forcing the deletion even if it does not exist. + * If an {@link IOException} occurs during the deletion process, it is logged but not propagated. + * + * @param file the {@link File} to be deleted; can be null, in which case nothing happens. + */ public static void deleteQuietlyForce(File file) { if (file != null) { try { Files.deleteIfExists(file.toPath()); } catch (IOException e) { - log.debug(e); - // ignored + log.error(e.getMessage(), e); } } } diff --git a/src/main/java/io/github/makbn/jthumbnail/core/util/ResizeImage.java b/src/main/java/io/github/makbn/jthumbnail/core/util/ResizeImage.java index 58a6a00..a8d61b9 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/util/ResizeImage.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/util/ResizeImage.java @@ -2,8 +2,8 @@ import io.github.makbn.jthumbnail.core.exception.UnsupportedInputFileFormatException; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; import javax.imageio.ImageIO; import java.awt.*; @@ -13,7 +13,7 @@ import java.io.InputStream; import java.util.concurrent.CompletableFuture; - +@Slf4j public class ResizeImage { /** @@ -35,8 +35,8 @@ public class ResizeImage { * If output image is bigger than input image, allow the output to be smaller than expected (the size of the input image) */ public static final int ALLOW_SMALLER = 32; - private static final Logger mLog = LogManager.getLogger("ResizeImage"); private static final int EXTRA_OPTIONS = DO_NOT_SCALE_UP; + @Setter private int resizeMethod = RESIZE_FIT_ONE_DIMENSION; private BufferedImage inputImage; private boolean isProcessed = false; @@ -149,20 +149,16 @@ private void paint() { CompletableFuture isImageReady = new CompletableFuture<>(); - boolean scalingComplete = graphics2D.drawImage(inputImage, offsetX, offsetY, scaledWidth, scaledHeight, (img, flags, x, y, width, height)-> { + boolean scalingComplete = graphics2D.drawImage(inputImage, offsetX, offsetY, scaledWidth, scaledHeight, (img, flags, x, y, width, height) -> { isImageReady.complete(true); return true; }); if (!scalingComplete) { - mLog.debug("ResizeImage: Scaling is not yet complete!"); + log.debug("ResizeImage: Scaling is not yet complete!"); CompletableFuture.allOf(isImageReady).join(); } graphics2D.dispose(); } - - public void setResizeMethod(int resizeFitBothDimensions) { - resizeMethod = resizeFitBothDimensions; - } } diff --git a/src/main/java/io/github/makbn/jthumbnail/core/util/mime/DocFileIdentifier.java b/src/main/java/io/github/makbn/jthumbnail/core/util/mime/DocFileIdentifier.java index a2260f0..a2b7d57 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/util/mime/DocFileIdentifier.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/util/mime/DocFileIdentifier.java @@ -19,14 +19,14 @@ public DocFileIdentifier() { public String identify(String mimeType, byte[] bytes, File file) { if (isOfficeFile(mimeType) && !DOC_MIME_TYPE.equals(mimeType)) { - try(FileInputStream stream = new FileInputStream(file); - HWPFDocument document = new HWPFDocument(stream)) { + try (FileInputStream stream = new FileInputStream(file); + HWPFDocument document = new HWPFDocument(stream)) { if (document.getRange().getEndOffset() > 0) { return DOC_MIME_TYPE; } - } catch (IOException | RuntimeException e) { + } catch (IOException | RuntimeException e) { log.debug(e); } } diff --git a/src/main/java/io/github/makbn/jthumbnail/core/util/mime/MP3FileIdentifier.java b/src/main/java/io/github/makbn/jthumbnail/core/util/mime/MP3FileIdentifier.java index 8e91165..a03b439 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/util/mime/MP3FileIdentifier.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/util/mime/MP3FileIdentifier.java @@ -1,5 +1,8 @@ package io.github.makbn.jthumbnail.core.util.mime; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; + import java.io.File; import java.util.ArrayList; import java.util.List; @@ -7,12 +10,12 @@ /** * created by Mehdi Akbarian-Rastaghi 2018-10-23 */ +@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) public class MP3FileIdentifier implements MimeTypeIdentifier { - protected List ext; + protected List ext = new ArrayList<>(); public MP3FileIdentifier() { - ext = new ArrayList<>(); ext.add("mp3"); } @@ -23,7 +26,6 @@ public String identify(String mimeType, byte[] bytes, File file) { @Override public List getExtensionsFor(String mimeType) { - return ext; } diff --git a/src/main/java/io/github/makbn/jthumbnail/core/util/mime/MPEGFileIdentifier.java b/src/main/java/io/github/makbn/jthumbnail/core/util/mime/MPEGFileIdentifier.java index df8a1a4..f2410ee 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/util/mime/MPEGFileIdentifier.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/util/mime/MPEGFileIdentifier.java @@ -1,5 +1,8 @@ package io.github.makbn.jthumbnail.core.util.mime; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; + import java.io.File; import java.util.ArrayList; import java.util.List; @@ -7,12 +10,11 @@ /** * created by Mehdi Akbarian-Rastaghi 2018-10-23 */ +@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) public class MPEGFileIdentifier implements MimeTypeIdentifier { - - protected List ext; + List ext = new ArrayList<>(); public MPEGFileIdentifier() { - ext = new ArrayList<>(); ext.add("mp4"); ext.add("mkv"); ext.add("ts"); diff --git a/src/main/java/io/github/makbn/jthumbnail/core/util/mime/MimeTypeDetector.java b/src/main/java/io/github/makbn/jthumbnail/core/util/mime/MimeTypeDetector.java index 8f21594..9500d51 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/util/mime/MimeTypeDetector.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/util/mime/MimeTypeDetector.java @@ -1,9 +1,8 @@ package io.github.makbn.jthumbnail.core.util.mime; import io.github.makbn.jthumbnail.core.exception.ThumbnailerException; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FilenameUtils; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.apache.tika.Tika; import java.io.File; @@ -18,9 +17,8 @@ /** * Wrapper class for MIME Identification of Files. */ +@Slf4j public class MimeTypeDetector { - - private static final Logger mLog = LogManager.getLogger(MimeTypeDetector.class); private static final Map outputThumbnailExtensionCache = new HashMap<>(); private final List extraIdentifiers; private final Map> extensionsCache = new HashMap<>(); @@ -81,18 +79,18 @@ public String getMimeType(File file) throws IOException { mimeType = file.toURI().toURL().openConnection().getContentType(); } catch (Exception e) { - mLog.debug(e.getMessage()); + log.debug(e.getMessage()); } - if (mimeType != null && mimeType.length() == 0) + if (mimeType != null && mimeType.isEmpty()) mimeType = null; // Identifiers may re-write MIME. for (MimeTypeIdentifier identifier : extraIdentifiers) mimeType = identifier.identify(mimeType, null, file); - mLog.info("Detected MIME-Type of {} is {}", file.getName(), mimeType); + log.info("Detected MIME-Type of {} is {}", file.getName(), mimeType); return mimeType; } @@ -151,7 +149,7 @@ protected List getExtensionsCached(String mimeType) { extensions.add("dotm"); } case "application/pdf" -> extensions.add("pdf"); - default -> mLog.warn("no ext found!"); + default -> log.warn("no ext found!"); } extensionsCache.put(mimeType, extensions); return extensions; diff --git a/src/main/java/io/github/makbn/jthumbnail/core/util/mime/Office2007FileIdentifier.java b/src/main/java/io/github/makbn/jthumbnail/core/util/mime/Office2007FileIdentifier.java index 9fc1438..04db79f 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/util/mime/Office2007FileIdentifier.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/util/mime/Office2007FileIdentifier.java @@ -1,8 +1,6 @@ package io.github.makbn.jthumbnail.core.util.mime; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import lombok.extern.slf4j.Slf4j; import java.io.*; import java.util.List; @@ -14,10 +12,9 @@ * Add detection of Office2007 files (and OpenOffice files). * Magic numbers don't help here, only introspection of the zip. */ +@Slf4j public class Office2007FileIdentifier implements MimeTypeIdentifier { - private static final Logger mLog = LogManager.getLogger("Office2007FileIdentifier"); - @Override public String identify(String mimeType, byte[] bytes, File file) { if (mimeType == null || mimeType.equals("application/zip") || mimeType.startsWith("application/vnd.")) { @@ -41,7 +38,7 @@ public String identify(String mimeType, byte[] bytes, File file) { } catch (ZipException e) { return mimeType; // Zip file damaged or whatever. Silently give up. } catch (IOException e) { - mLog.error(e); + log.error(e.getMessage(), e); return mimeType; // Zip file damaged or whatever. Silently give up. } } diff --git a/src/main/java/io/github/makbn/jthumbnail/core/util/mime/OfficeFileIdentifier.java b/src/main/java/io/github/makbn/jthumbnail/core/util/mime/OfficeFileIdentifier.java index fa5d278..7e9c8ce 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/util/mime/OfficeFileIdentifier.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/util/mime/OfficeFileIdentifier.java @@ -1,5 +1,9 @@ package io.github.makbn.jthumbnail.core.util.mime; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.experimental.FieldDefaults; + import java.util.ArrayList; import java.util.List; @@ -9,20 +13,15 @@ * Requires: * - POI (version 3.7 or higher) */ +@FieldDefaults(makeFinal = true, level = AccessLevel.PROTECTED) +@NoArgsConstructor(access = AccessLevel.PROTECTED) public abstract class OfficeFileIdentifier implements MimeTypeIdentifier { - protected static final String PPT_MIME_TYPE = "application/vnd.ms-powerpoint"; protected static final String XLS_MIME_TYPE = "application/vnd.ms-excel"; protected static final String DOC_MIME_TYPE = "application/vnd.ms-word"; - protected static final String MS_OFFICE_MIME_TYPE = "application/vnd.ms-office"; - - protected List ext; - - protected OfficeFileIdentifier() { - ext = new ArrayList<>(); - } + List ext = new ArrayList<>(); @Override public List getExtensionsFor(String mimeType) { diff --git a/src/main/java/io/github/makbn/jthumbnail/core/util/mime/PptFileIdentifier.java b/src/main/java/io/github/makbn/jthumbnail/core/util/mime/PptFileIdentifier.java index 61d3ffc..d1b55c3 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/util/mime/PptFileIdentifier.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/util/mime/PptFileIdentifier.java @@ -19,7 +19,6 @@ public PptFileIdentifier() { @Override public String identify(String mimeType, byte[] bytes, File file) { - if (isOfficeFile(mimeType) && !PPT_MIME_TYPE.equals(mimeType)) { try(FileInputStream stream = new FileInputStream(file); HSLFSlideShow presentation = new HSLFSlideShow(stream)) { if (!presentation.getSlides().isEmpty()) { diff --git a/src/main/java/io/github/makbn/jthumbnail/core/util/mime/XlsFileIdentifier.java b/src/main/java/io/github/makbn/jthumbnail/core/util/mime/XlsFileIdentifier.java index a5bf299..b148071 100644 --- a/src/main/java/io/github/makbn/jthumbnail/core/util/mime/XlsFileIdentifier.java +++ b/src/main/java/io/github/makbn/jthumbnail/core/util/mime/XlsFileIdentifier.java @@ -1,6 +1,7 @@ package io.github.makbn.jthumbnail.core.util.mime; import lombok.extern.log4j.Log4j2; +import lombok.extern.slf4j.Slf4j; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.poifs.filesystem.OfficeXmlFileException; @@ -8,7 +9,7 @@ import java.io.FileInputStream; import java.io.IOException; -@Log4j2 +@Slf4j public class XlsFileIdentifier extends OfficeFileIdentifier { public XlsFileIdentifier() { @@ -25,7 +26,7 @@ public String identify(String mimeType, byte[] bytes, File file) { return XLS_MIME_TYPE; } } catch (IOException | OfficeXmlFileException e) { - log.debug(e); + log.debug(e.getMessage(), e); } } diff --git a/src/test/java/io/github/makbn/jthumbnail/ThumbnailerTest.java b/src/test/java/io/github/makbn/jthumbnail/ThumbnailerTest.java index bafa1f4..0ef9984 100644 --- a/src/test/java/io/github/makbn/jthumbnail/ThumbnailerTest.java +++ b/src/test/java/io/github/makbn/jthumbnail/ThumbnailerTest.java @@ -15,6 +15,7 @@ import java.io.File; import java.io.IOException; +import java.nio.file.CopyOption; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; @@ -40,7 +41,11 @@ public static void init() throws IOException { @AfterAll public static void destroy() { - jThumbnailer.close(); + try { + jThumbnailer.close(); + }catch (Exception e) { + System.exit(0); + } } @ParameterizedTest @@ -62,7 +67,7 @@ void genThumb(String filePath, String uniqueCode) throws InterruptedException { final String[] msg = new String[2]; if (in.exists()) { - ThumbnailCandidate candidate = new ThumbnailCandidate(in, uniqueCode); + ThumbnailCandidate candidate = ThumbnailCandidate.of(in, uniqueCode); jThumbnailer.run(candidate, new ThumbnailListener() { @Override public void onThumbnailReady(String hash, File thumbnail) {