diff --git a/jpro-image-manager/src/main/java/one/jpro/platform/image/manager/ImageDefinition.java b/jpro-image-manager/src/main/java/one/jpro/platform/image/manager/ImageDefinition.java index dca690d6..4f8443f3 100644 --- a/jpro-image-manager/src/main/java/one/jpro/platform/image/manager/ImageDefinition.java +++ b/jpro-image-manager/src/main/java/one/jpro/platform/image/manager/ImageDefinition.java @@ -81,11 +81,10 @@ public ImageEncoder getEncoder() { /** * Computes and returns a hash string representation for this instance. - * Note: This method currently returns the default hashCode as a string, which might not guarantee uniqueness. * * @return A string representing the hash of this instance. */ String getHashString() { - return Integer.toString(hashCode()); + return ImageManager.computeImageDefinitionHash(this); } } \ No newline at end of file diff --git a/jpro-image-manager/src/main/java/one/jpro/platform/image/manager/ImageManager.java b/jpro-image-manager/src/main/java/one/jpro/platform/image/manager/ImageManager.java index e0f4f234..a8ceecb8 100644 --- a/jpro-image-manager/src/main/java/one/jpro/platform/image/manager/ImageManager.java +++ b/jpro-image-manager/src/main/java/one/jpro/platform/image/manager/ImageManager.java @@ -151,7 +151,7 @@ CompletableFuture loadFXImageFuture(ImageSource source, ImageTransformer * @param imageDefinition the image definition * @return the computed MD5 hash as a string */ - private String computeImageDefinitionHash(ImageDefinition imageDefinition) { + public static String computeImageDefinitionHash(ImageDefinition imageDefinition) { try { MessageDigest digest = MessageDigest.getInstance("MD5"); byte[] hashBytes = digest.digest(imageDefinition.toJSON().toString().getBytes(StandardCharsets.UTF_8)); diff --git a/jpro-image-manager/src/main/java/one/jpro/platform/image/manager/source/ImageSourceFile.java b/jpro-image-manager/src/main/java/one/jpro/platform/image/manager/source/ImageSourceFile.java index 9e7d890c..fad67d35 100644 --- a/jpro-image-manager/src/main/java/one/jpro/platform/image/manager/source/ImageSourceFile.java +++ b/jpro-image-manager/src/main/java/one/jpro/platform/image/manager/source/ImageSourceFile.java @@ -69,6 +69,7 @@ public JSONObject toJSON() { JSONObject json = new JSONObject(); json.put("type", getClass().getSimpleName()); json.put("path", ImageUtils.escapeJson(file.getAbsolutePath())); + json.put("modified", file.lastModified()); return json; } } \ No newline at end of file diff --git a/jpro-image-manager/src/main/java/one/jpro/platform/image/manager/source/ImageSourceResource.java b/jpro-image-manager/src/main/java/one/jpro/platform/image/manager/source/ImageSourceResource.java index 85f269ec..d6e59583 100644 --- a/jpro-image-manager/src/main/java/one/jpro/platform/image/manager/source/ImageSourceResource.java +++ b/jpro-image-manager/src/main/java/one/jpro/platform/image/manager/source/ImageSourceResource.java @@ -67,8 +67,18 @@ public long identityHashValue() { public JSONObject toJSON() { JSONObject json = new JSONObject(); json.put("type", getClass().getSimpleName()); - // Escaping might be necessary depending on the structure of resourcePath. json.put("resourcePath", ImageUtils.escapeJson(resourcePath)); + // get last modified date + // It's important, so the images get recreated, when the files in the jar are updated + try { + URL resourceUrl = getClass().getResource(resourcePath); + if (resourceUrl != null) { + URLConnection conn = resourceUrl.openConnection(); + json.put("modified", conn.getLastModified()); + } + } catch (Exception ex) { + throw new RuntimeException("Error obtaining modification date for resource: " + resourcePath, ex); + } return json; } diff --git a/jpro-image-manager/src/test/java/one/jpro/platform/image/manager/ImageManagerTest.java b/jpro-image-manager/src/test/java/one/jpro/platform/image/manager/ImageManagerTest.java index 05e87483..d7fb0366 100644 --- a/jpro-image-manager/src/test/java/one/jpro/platform/image/manager/ImageManagerTest.java +++ b/jpro-image-manager/src/test/java/one/jpro/platform/image/manager/ImageManagerTest.java @@ -14,8 +14,12 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import java.io.IOException; +import java.nio.file.Files; + import java.awt.image.BufferedImage; import java.io.File; +import java.nio.file.StandardCopyOption; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; @@ -26,6 +30,9 @@ class ImageManagerTest { ImageManager manager; ImageDefinition def; + File imageDef2File; + ImageDefinition imageDef2; + @BeforeEach @@ -44,6 +51,12 @@ void setUp() throws InterruptedException { ImageTransformer transformer = new ImageTransformerFitWidth(200); ImageEncoder encoder = new ImageEncoderPNG(); def = new ImageDefinition(source, transformer, encoder); + + imageDef2File = new File("testImage.png"); + ImageSource source2 = new ImageSourceFile(imageDef2File); + ImageTransformer transformer2 = new ImageTransformerFitWidth(200); + ImageEncoder encoder2 = new ImageEncoderPNG(); + imageDef2 = new ImageDefinition(source2, transformer2, encoder2); } @Test @@ -68,6 +81,41 @@ void testImageNotCreatedTwice() { assertEquals(imageFileBefore.lastModified(), imageFileAfter.lastModified(), "Image was created again."); } + @Test + void testImageRecreateOnChange() throws IOException { + // Copy file1 to imageDef2File + File file1 = new File(getClass().getResource("/testImage.png").getFile()); + File file2 = new File(getClass().getResource("/logo.png").getFile()); + assertTrue(file1.exists()); + assertTrue(file2.exists()); + + Files.copy(file1.toPath(), imageDef2File.toPath(), StandardCopyOption.REPLACE_EXISTING); + + var image1 = manager.loadImage(imageDef2); + String hash1 = imageDef2.getHashString(); + + Files.copy(file2.toPath(), imageDef2File.toPath(), StandardCopyOption.REPLACE_EXISTING); + + var image2 = manager.loadImage(imageDef2); + String hash2 = imageDef2.getHashString(); + + System.out.println("hash1: " + hash1); + System.out.println("hash2: " + hash2); + assertNotEquals(hash1, hash2, "changed image file should have different hash"); + + File imageFile1 = image1.getFile(); + File imageFile2 = image2.getFile(); + + assertTrue(imageFile1.exists()); + assertTrue(imageFile2.exists()); + + System.out.println("imageFile1: " + imageFile1.lastModified()); + System.out.println("imageFile2: " + imageFile2.lastModified()); + + assertNotEquals(imageFile1.lastModified(), imageFile2.lastModified(), + "Image was not created again."); + } + @Test void testLoadImageFuture() { CompletableFuture future = manager.loadImageFuture(def);