diff --git a/actions/pom.xml b/actions/pom.xml
index 7f76bef9..683451ba 100644
--- a/actions/pom.xml
+++ b/actions/pom.xml
@@ -23,11 +23,11 @@
tools.dynamiatools.dynamia.parent
- 5.4.11
+ 5.4.12tools.dynamia.actions
- 5.4.11
+ 5.4.12DynamiaTools - Actionshttps://dynamia.tools/docs/actions
@@ -65,12 +65,12 @@
tools.dynamiatools.dynamia.integration
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.commons
- 5.4.11
+ 5.4.12
diff --git a/app/pom.xml b/app/pom.xml
index b137b7cb..9eca2298 100644
--- a/app/pom.xml
+++ b/app/pom.xml
@@ -23,11 +23,11 @@
tools.dynamiatools.dynamia.parent
- 5.4.11
+ 5.4.12tools.dynamia.app
- 5.4.11
+ 5.4.12DynamiaTools - Apphttps://dynamia.tools/docs/app
@@ -74,58 +74,58 @@
tools.dynamiatools.dynamia.actions
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.commons
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.crud
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.domain
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.integration
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.io
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.navigation
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.reports
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.templates
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.viewers
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.web
- 5.4.11
+ 5.4.12org.springframework.data
@@ -208,7 +208,7 @@
tools.dynamiatools.dynamia.domain.jpa
- 5.4.11
+ 5.4.12test
diff --git a/app/src/main/java/tools/dynamia/app/controllers/CrudServiceRestController.java b/app/src/main/java/tools/dynamia/app/controllers/CrudServiceRestController.java
index e8fc626e..f608ee14 100644
--- a/app/src/main/java/tools/dynamia/app/controllers/CrudServiceRestController.java
+++ b/app/src/main/java/tools/dynamia/app/controllers/CrudServiceRestController.java
@@ -1,7 +1,7 @@
package tools.dynamia.app.controllers;
import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.json.JsonMapper;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@@ -43,7 +43,7 @@ public class CrudServiceRestController {
/**
* JSON object mapper for entity serialization/deserialization.
*/
- private final ObjectMapper mapper = StringPojoParser.createJsonMapper();
+ private final JsonMapper mapper = StringPojoParser.createJsonMapper();
/**
* Constructs a new {@code CrudServiceRestController} with the given CRUD service.
diff --git a/commons/pom.xml b/commons/pom.xml
index 12fbec5d..bdaff51b 100644
--- a/commons/pom.xml
+++ b/commons/pom.xml
@@ -22,11 +22,10 @@
tools.dynamia.commonsjar
- 5.4.11tools.dynamiatools.dynamia.parent
- 5.4.11
+ 5.4.12DynamiaTools - Commonshttps://dynamia.tools/docs/common
diff --git a/commons/src/main/java/tools/dynamia/commons/StringPojoParser.java b/commons/src/main/java/tools/dynamia/commons/StringPojoParser.java
index 425d2c73..da55d078 100644
--- a/commons/src/main/java/tools/dynamia/commons/StringPojoParser.java
+++ b/commons/src/main/java/tools/dynamia/commons/StringPojoParser.java
@@ -20,7 +20,6 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
-import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
@@ -53,7 +52,7 @@ public static String convertMapToJson(Map map) {
if (map == null || map.isEmpty()) {
return "";
}
- ObjectMapper jsonMapper = createJsonMapper();
+ var jsonMapper = createJsonMapper();
return jsonMapper.writeValueAsString(map);
} catch (JsonProcessingException e) {
throw new JsonParsingException(e);
@@ -61,11 +60,11 @@ public static String convertMapToJson(Map map) {
}
/**
- * Creates a configured JSON {@link ObjectMapper} with indentation, disabled empty beans, and JavaTimeModule support.
+ * Creates a configured JSON {@link JsonMapper} with indentation, disabled empty beans, and JavaTimeModule support.
*
* @return the configured JSON ObjectMapper
*/
- public static ObjectMapper createJsonMapper() {
+ public static JsonMapper createJsonMapper() {
return JsonMapper.builder()
.enable(SerializationFeature.INDENT_OUTPUT)
.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
@@ -85,7 +84,7 @@ public static String convertPojoToJson(Object pojo) {
if (pojo == null) {
return "";
}
- ObjectMapper jsonMapper = createJsonMapper();
+ var jsonMapper = createJsonMapper();
return jsonMapper.writeValueAsString(pojo);
} catch (JsonProcessingException e) {
throw new JsonParsingException(e);
@@ -141,7 +140,7 @@ public static T parseJsonToPojo(String json, Class pojoType) {
return null;
}
- ObjectMapper jsonMapper = createJsonMapper();
+ var jsonMapper = createJsonMapper();
return jsonMapper.readerFor(pojoType).readValue(json);
} catch (IOException e) {
throw new JsonParsingException(e);
@@ -161,7 +160,7 @@ public static T parseJsonToPojo(Map map, Class pojoType) {
return null;
}
- ObjectMapper jsonMapper = createJsonMapper();
+ var jsonMapper = createJsonMapper();
return jsonMapper.convertValue(map, pojoType);
} catch (IllegalArgumentException e) {
throw new JsonParsingException(e);
@@ -184,12 +183,12 @@ public static String convertPojoToXml(Object pojo) {
}
/**
- * Create a xml {@link ObjectMapper} with enable IDENT_OUTPUT and disabled FAIL_ON_EMPTY_BEANS. Also add support
+ * Create a xml {@link XmlMapper} with enable IDENT_OUTPUT and disabled FAIL_ON_EMPTY_BEANS. Also add support
* to {@link JavaTimeModule} from JSR310 dependency
*
- * @return xml ObjectMapper
+ * @return xml mapper
*/
- public static ObjectMapper createXmlMapper() {
+ public static XmlMapper createXmlMapper() {
return XmlMapper.builder()
.enable(SerializationFeature.INDENT_OUTPUT)
.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
@@ -244,7 +243,7 @@ public static String convertListToJson(List list) {
if (list == null || list.isEmpty()) {
return "";
}
- ObjectMapper jsonMapper = createJsonMapper();
+ var jsonMapper = createJsonMapper();
return jsonMapper.writeValueAsString(list);
} catch (JsonProcessingException e) {
throw new JsonParsingException(e);
diff --git a/commons/src/main/java/tools/dynamia/commons/math/Randoms.java b/commons/src/main/java/tools/dynamia/commons/math/Randoms.java
new file mode 100644
index 00000000..0b8ef3dd
--- /dev/null
+++ b/commons/src/main/java/tools/dynamia/commons/math/Randoms.java
@@ -0,0 +1,297 @@
+package tools.dynamia.commons.math;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * Utility class for generating random numbers and strings.
+ * Uses {@link ThreadLocalRandom} for better performance in concurrent environments.
+ */
+public class Randoms {
+
+ /**
+ * Returns a random integer between the specified origin (inclusive) and the specified bound (exclusive).
+ *
+ * @param min the least value returned
+ * @param max the upper bound (exclusive)
+ * @return a random integer between {@code min} (inclusive) and {@code max} (exclusive)
+ */
+ public static int nextInt(int min, int max) {
+ return ThreadLocalRandom.current().nextInt(min, max);
+ }
+
+ /**
+ * Returns a random integer between 0 (inclusive) and the specified bound (exclusive).
+ *
+ * @param max the upper bound (exclusive)
+ * @return a random integer between 0 (inclusive) and {@code max} (exclusive)
+ */
+ public static int nextInt(int max) {
+ return ThreadLocalRandom.current().nextInt(max);
+ }
+
+ /**
+ * Returns a random integer.
+ *
+ * @return a random integer
+ */
+ public static int nextInt() {
+ return ThreadLocalRandom.current().nextInt(0, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Returns a random long between the specified origin (inclusive) and the specified bound (exclusive).
+ *
+ * @param min the least value returned
+ * @param max the upper bound (exclusive)
+ * @return a random long between {@code min} (inclusive) and {@code max} (exclusive)
+ */
+ public static long nextLong(long min, long max) {
+ return ThreadLocalRandom.current().nextLong(min, max);
+ }
+
+ /**
+ * Returns a random float between the specified origin (inclusive) and the specified bound (exclusive).
+ *
+ * @param min the least value returned
+ * @param max the upper bound (exclusive)
+ * @return a random float between {@code min} (inclusive) and {@code max} (exclusive)
+ */
+ public static float nextFloat(float min, float max) {
+ return min + ThreadLocalRandom.current().nextFloat() * (max - min);
+ }
+
+ /**
+ * Returns a random double between the specified origin (inclusive) and the specified bound (exclusive).
+ *
+ * @param min the least value returned
+ * @param max the upper bound (exclusive)
+ * @return a random double between {@code min} (inclusive) and {@code max} (exclusive)
+ */
+ public static double nextDouble(double min, double max) {
+ return ThreadLocalRandom.current().nextDouble(min, max);
+ }
+
+ /**
+ * Generates a random string of the specified length using alphanumeric characters.
+ *
+ * @param length the length of the random string
+ * @return a random string of alphanumeric characters
+ */
+ public static String nextString(int length) {
+ StringBuilder sb = new StringBuilder();
+ String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+ for (int i = 0; i < length; i++) {
+ int index = nextInt(chars.length());
+ sb.append(chars.charAt(index));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Generates a random string of the specified length using numeric characters.
+ *
+ * @param length the length of the random string
+ * @return a random string of numeric characters
+ */
+ public static String nextNumericString(int length) {
+ StringBuilder sb = new StringBuilder();
+ String chars = "0123456789";
+ for (int i = 0; i < length; i++) {
+ int index = nextInt(chars.length());
+ sb.append(chars.charAt(index));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Generates a random string of the specified length using alphabetic characters.
+ *
+ * @param length the length of the random string
+ * @return a random string of alphabetic characters
+ */
+ public static String nextAlphabeticString(int length) {
+ StringBuilder sb = new StringBuilder();
+ String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ for (int i = 0; i < length; i++) {
+ int index = nextInt(chars.length());
+ sb.append(chars.charAt(index));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Generates a random string of the specified length using hexadecimal characters.
+ *
+ * @param length the length of the random string
+ * @return a random string of hexadecimal characters
+ */
+ public static String nextHexString(int length) {
+ StringBuilder sb = new StringBuilder();
+ String chars = "0123456789ABCDEF";
+ for (int i = 0; i < length; i++) {
+ int index = nextInt(chars.length());
+ sb.append(chars.charAt(index));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Generates a random hex color string (e.g., #FF0000).
+ *
+ * @return a random hex color string
+ */
+ public static String nextHexColor() {
+ return "#" + nextHexString(6);
+ }
+
+ /**
+ * Generates a random UUID string.
+ *
+ * @return a random UUID string
+ */
+ public static String nextUUID() {
+ return java.util.UUID.randomUUID().toString();
+ }
+
+ /**
+ * Returns a random name from a predefined list of names.
+ *
+ * @return a random name
+ */
+ public static String nextName() {
+ String[] names = {"Alice", "Bob", "Charlie", "David", "Eve", "Frank", "Grace", "Hannah", "Ivy", "Jack",
+ "Kathy", "Liam", "Mia", "Noah", "Olivia", "Paul", "Quinn", "Rachel", "Sam", "Tina",
+ "Uma", "Victor", "Wendy", "Xander", "Yara", "Zane", "Aaron", "Bella", "Carter", "Diana", "Ethan", "Fiona",
+ "Gavin", "Hailey", "Ian", "Jasmine", "Kevin", "Luna", "Mason", "Nora", "Owen", "Piper", "Quincy", "Ruby", "Sean", "Tara",
+ "Mario", "Nina", "Leo", "Eva", "Jake", "Lily", "Cindy", "Derek", "Elena", "Felix", "Gloria"};
+ return names[nextInt(names.length)];
+ }
+
+ /**
+ * Returns a random element from the specified array.
+ *
+ * @param the type of the elements
+ * @param array the array to choose from
+ * @return a random element from the array, or {@code null} if the array is null or empty
+ */
+ public static T chooseRandom(T[] array) {
+ if (array == null || array.length == 0) {
+ return null;
+ }
+ int index = nextInt(array.length);
+ return array[index];
+ }
+
+ /**
+ * Returns a random element from the specified array, or the default value if the array is null or empty.
+ *
+ * @param the type of the elements
+ * @param array the array to choose from
+ * @param defaultValue the value to return if the array is null or empty
+ * @return a random element from the array, or {@code defaultValue}
+ */
+ public static T chooseRandom(T[] array, T defaultValue) {
+ if (array == null || array.length == 0) {
+ return defaultValue;
+ }
+
+ int index = nextInt(array.length);
+ return array[index];
+ }
+
+ /**
+ * Returns a random element from the specified list.
+ *
+ * @param the type of the elements
+ * @param list the list to choose from
+ * @return a random element from the list, or {@code null} if the list is null or empty
+ */
+ public static T chooseRandom(java.util.List list) {
+ if (list == null || list.isEmpty()) {
+ return null;
+ }
+ int index = nextInt(list.size());
+ return list.get(index);
+ }
+
+ /**
+ * Returns a random date between the specified start (inclusive) and end (exclusive) dates.
+ *
+ * @param startInclusive the start date (inclusive)
+ * @param endExclusive the end date (exclusive)
+ * @return a random date between {@code startInclusive} and {@code endExclusive}
+ */
+ public static LocalDate nextDate(LocalDate startInclusive, LocalDate endExclusive) {
+ long startEpochDay = startInclusive.toEpochDay();
+ long endEpochDay = endExclusive.toEpochDay();
+ long randomDay = nextLong(startEpochDay, endEpochDay);
+ return LocalDate.ofEpochDay(randomDay);
+ }
+
+ /**
+ * Returns a random date in the past, up to the specified maximum number of days.
+ *
+ * @param maxDaysInPast the maximum number of days in the past
+ * @return a random date in the past
+ */
+ public static LocalDate nextPastDate(int maxDaysInPast) {
+ LocalDate today = LocalDate.now();
+ long randomDays = nextLong(1, maxDaysInPast + 1);
+ return today.minusDays(randomDays);
+ }
+
+ /**
+ * Returns a random date in the future, up to the specified maximum number of days.
+ *
+ * @param maxDaysInFuture the maximum number of days in the future
+ * @return a random date in the future
+ */
+ public static LocalDate nextFutureDate(int maxDaysInFuture) {
+ LocalDate today = LocalDate.now();
+ long randomDays = nextLong(1, maxDaysInFuture + 1);
+ return today.plusDays(randomDays);
+ }
+
+ /**
+ * Returns a random date-time between the specified start (inclusive) and end (exclusive) date-times.
+ *
+ * @param startInclusive the start date-time (inclusive)
+ * @param endExclusive the end date-time (exclusive)
+ * @return a random date-time between {@code startInclusive} and {@code endExclusive}
+ */
+ public static LocalDateTime nextDateTime(LocalDateTime startInclusive, LocalDateTime endExclusive) {
+ long startEpochSecond = startInclusive.toEpochSecond(java.time.ZoneOffset.UTC);
+ long endEpochSecond = endExclusive.toEpochSecond(java.time.ZoneOffset.UTC);
+ long randomSecond = nextLong(startEpochSecond, endEpochSecond);
+ return LocalDateTime.ofEpochSecond(randomSecond, 0, java.time.ZoneOffset.UTC);
+ }
+
+ /**
+ * Returns a random time of day.
+ *
+ * @return a random time
+ */
+ public static LocalTime nextTime() {
+ int hour = nextInt(0, 24);
+ int minute = nextInt(0, 60);
+ int second = nextInt(0, 60);
+ return LocalTime.of(hour, minute, second);
+ }
+
+ /**
+ * Returns a random time between the specified minimum hour (inclusive) and maximum hour (exclusive).
+ *
+ * @param minHour the minimum hour (inclusive)
+ * @param maxHour the maximum hour (exclusive)
+ * @return a random time between {@code minHour} and {@code maxHour}
+ */
+ public static LocalTime nextTime(int minHour, int maxHour) {
+ int hour = nextInt(minHour, maxHour);
+ int minute = nextInt(0, 60);
+ int second = nextInt(0, 60);
+ return LocalTime.of(hour, minute, second);
+ }
+}
diff --git a/crud/pom.xml b/crud/pom.xml
index 7ff6c992..607eff86 100644
--- a/crud/pom.xml
+++ b/crud/pom.xml
@@ -23,11 +23,11 @@
tools.dynamiatools.dynamia.parent
- 5.4.11
+ 5.4.12tools.dynamia.crud
- 5.4.11
+ 5.4.12DynamiaTools - CRUDhttps://dynamia.tools/docs/crud
@@ -62,23 +62,23 @@
tools.dynamiatools.dynamia.actions
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.viewers
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.navigation
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.domain.jpa
- 5.4.11
+ 5.4.12test
diff --git a/domain-jpa/pom.xml b/domain-jpa/pom.xml
index 15b8fd3b..10f1a9a8 100644
--- a/domain-jpa/pom.xml
+++ b/domain-jpa/pom.xml
@@ -23,13 +23,13 @@
tools.dynamiatools.dynamia.parent
- 5.4.11
+ 5.4.12DynamiaTools - Domain JPAhttps://dynamia.tools/docs/domaintools.dynamia.domain.jpa
- 5.4.11
+ 5.4.12jar
diff --git a/domain/pom.xml b/domain/pom.xml
index ee105d0e..b80debd0 100644
--- a/domain/pom.xml
+++ b/domain/pom.xml
@@ -21,13 +21,13 @@
4.0.0tools.dynamia.domain
- 5.4.11
+ 5.4.12jartools.dynamiatools.dynamia.parent
- 5.4.11
+ 5.4.12DynamiaTools - Domainhttps://dynamia.tools/docs/domain
diff --git a/integration/pom.xml b/integration/pom.xml
index 9be0885f..c0fbc78c 100644
--- a/integration/pom.xml
+++ b/integration/pom.xml
@@ -27,12 +27,12 @@
tools.dynamiatools.dynamia.parent
- 5.4.11
+ 5.4.12DynamiaTools - IntegrationA set of classes and interfaces that help integrate modules
- 5.4.11
+ 5.4.12https://dynamia.tools/docs/integration
diff --git a/integration/src/main/java/tools/dynamia/integration/scheduling/SchedulerUtil.java b/integration/src/main/java/tools/dynamia/integration/scheduling/SchedulerUtil.java
index 2c5de048..9c1985ba 100644
--- a/integration/src/main/java/tools/dynamia/integration/scheduling/SchedulerUtil.java
+++ b/integration/src/main/java/tools/dynamia/integration/scheduling/SchedulerUtil.java
@@ -53,29 +53,22 @@ public class SchedulerUtil {
* Execute a task asynchronously using a Virtual Thread executor from {@link VT} helper class.
*
* @param task the runnable
+ * @return a completable future
*/
- public static void run(Runnable task) {
+ public static CompletableFuture run(Runnable task) {
Runnable runnableWithContext = getWithContext(task);
- VT.executor().execute(runnableWithContext);
+ return CompletableFuture.runAsync(runnableWithContext, VT.executor());
}
/**
* Execute a task using a Virtual Thread executor from {@link VT} helper class and wait for its completion
- * or timeout.
+ * or timeout. This is a shorthand for run(task).get(timeout).
*
* @param task the runnable
* @param timeout the timeout
*/
public static void runAndWait(Runnable task, Duration timeout) {
- CompletableFuture future = new CompletableFuture<>();
- run(() -> {
- try {
- task.run();
- future.complete(null);
- } catch (Exception e) {
- future.completeExceptionally(e);
- }
- });
+ CompletableFuture future = run(task);
try {
future.get(timeout.toMillis(), TimeUnit.MILLISECONDS);
@@ -90,6 +83,7 @@ public static void runAndWait(Runnable task, Duration timeout) {
*
* @param firstTask the first task
* @param others the tasks
+ * @return the completable future
*/
public static CompletableFuture run(Runnable firstTask, Runnable... others) {
diff --git a/io/pom.xml b/io/pom.xml
index 237b518b..bf7c79cb 100644
--- a/io/pom.xml
+++ b/io/pom.xml
@@ -28,11 +28,11 @@
tools.dynamiatools.dynamia.parent
- 5.4.11
+ 5.4.12DynamiaTools - IO
- 5.4.11
+ 5.4.12A set of classes and interfaces that help in any kind io taskhttps://dynamia.tools/docs/io
diff --git a/navigation/pom.xml b/navigation/pom.xml
index 752b97b3..c56be039 100644
--- a/navigation/pom.xml
+++ b/navigation/pom.xml
@@ -23,11 +23,11 @@
tools.dynamiatools.dynamia.parent
- 5.4.11
+ 5.4.12tools.dynamia.navigation
- 5.4.11
+ 5.4.12DynamiaTools - Navigationhttps://dynamia.tools/docs/navigation
@@ -63,17 +63,17 @@
tools.dynamiatools.dynamia.commons
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.integration
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.actions
- 5.4.11
+ 5.4.12
diff --git a/navigation/src/main/java/tools/dynamia/navigation/BaseNavigationManager.java b/navigation/src/main/java/tools/dynamia/navigation/BaseNavigationManager.java
index 3c76dc80..3817b891 100644
--- a/navigation/src/main/java/tools/dynamia/navigation/BaseNavigationManager.java
+++ b/navigation/src/main/java/tools/dynamia/navigation/BaseNavigationManager.java
@@ -243,11 +243,16 @@ public void navigateTo(String path) {
*/
@Override
public void navigateTo(String path, Map params) {
- if (!path.contains("/")) {
- setActiveModule(container.getModuleById(path));
- } else {
- Page page = findPage(path);
- setCurrentPage(page, params);
+ if(path!=null) {
+ path = path.trim();
+ if (!path.contains("/")) {
+ setActiveModule(container.getModuleById(path));
+ } else {
+ Page page = findPage(path);
+ setCurrentPage(page, params);
+ }
+ }else{
+ logger.warn("path is null, cannot navigate");
}
}
diff --git a/pom.xml b/pom.xml
index 870304ff..3fbe8d80 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,7 +24,7 @@
4.0.0tools.dynamiatools.dynamia.parent
- 5.4.11
+ 5.4.12pomDynamia Soluciones IT SAS
@@ -80,7 +80,7 @@
${project.baseUri}
- 3.5.8
+ 3.5.92.2.381
diff --git a/reports/pom.xml b/reports/pom.xml
index 0766b79e..3fee21b6 100644
--- a/reports/pom.xml
+++ b/reports/pom.xml
@@ -26,11 +26,11 @@
tools.dynamiatools.dynamia.parent
- 5.4.11
+ 5.4.12DynamiaTools - Reports
- 5.4.11
+ 5.4.12A set of classes and interfaces that help building Reportshttps://dynamia.tools/docs/reports
diff --git a/starter/pom.xml b/starter/pom.xml
index 1c1fd00b..27ce261a 100644
--- a/starter/pom.xml
+++ b/starter/pom.xml
@@ -4,7 +4,7 @@
tools.dynamiatools.dynamia.parent
- 5.4.11
+ 5.4.12dynamia-tools-starterDynamiaTools - Starter
@@ -26,17 +26,22 @@
tools.dynamiatools.dynamia.app
- 5.4.11
+ 5.4.12
+
+
+ tools.dynamia
+ tools.dynamia.commons
+ 5.4.12tools.dynamiatools.dynamia.zk
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.domain.jpa
- 5.4.11
+ 5.4.12org.hibernate.validator
@@ -46,7 +51,7 @@
org.springdocspringdoc-openapi-starter-webmvc-api
- 2.8.4
+ 2.8.12
@@ -59,7 +64,7 @@
org.springframework.bootspring-boot-maven-plugin
- 3.4.4
+ ${springboot.version}-Dspring.application.admin.enabled=true
diff --git a/templates/pom.xml b/templates/pom.xml
index 83632e47..9fbfead2 100644
--- a/templates/pom.xml
+++ b/templates/pom.xml
@@ -23,12 +23,12 @@
tools.dynamia.parenttools.dynamia
- 5.4.11
+ 5.4.12tools.dynamia.templates
- 5.4.11
+ 5.4.12DynamiaTools - Templateshttps://dynamia.tools/docs/templates
@@ -64,12 +64,12 @@
tools.dynamiatools.dynamia.integration
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.commons
- 5.4.11
+ 5.4.12
diff --git a/ui/pom.xml b/ui/pom.xml
index c744d8d4..63b4b300 100644
--- a/ui/pom.xml
+++ b/ui/pom.xml
@@ -23,11 +23,11 @@
tools.dynamiatools.dynamia.parent
- 5.4.11
+ 5.4.12tools.dynamia.ui
- 5.4.11
+ 5.4.12DynamiaTools - UIhttps://dynamia.tools/docs/uiHelper classes for module integrations and messages
@@ -64,17 +64,17 @@
tools.dynamiatools.dynamia.integration
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.commons
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.io
- 5.4.11
+ 5.4.12
diff --git a/viewers/pom.xml b/viewers/pom.xml
index 75fca7b8..cbb57442 100644
--- a/viewers/pom.xml
+++ b/viewers/pom.xml
@@ -23,13 +23,13 @@
tools.dynamia.viewersjar
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.parent
- 5.4.11
+ 5.4.12DynamiaTools - Viewers
@@ -67,27 +67,27 @@
tools.dynamiatools.dynamia.commons
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.integration
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.io
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.domain
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.actions
- 5.4.11
+ 5.4.12org.yaml
diff --git a/viewers/src/main/java/tools/dynamia/viewers/JsonView.java b/viewers/src/main/java/tools/dynamia/viewers/JsonView.java
index 8155d72c..279e9141 100644
--- a/viewers/src/main/java/tools/dynamia/viewers/JsonView.java
+++ b/viewers/src/main/java/tools/dynamia/viewers/JsonView.java
@@ -18,9 +18,9 @@
package tools.dynamia.viewers;
import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
+import tools.dynamia.commons.StringPojoParser;
import java.io.IOException;
@@ -31,7 +31,7 @@ public class JsonView implements View {
private T value;
private View parentView;
private ViewDescriptor viewDescriptor;
- private ObjectMapper mapper;
+ private JsonMapper mapper;
public JsonView() {
@@ -80,7 +80,7 @@ public void setViewDescriptor(ViewDescriptor viewDescriptor) {
public String renderJson() {
try {
- ObjectMapper mapper = getObjectMapper();
+ var mapper = getJsonMapper();
return mapper.writeValueAsString(value);
} catch (JsonProcessingException e) {
throw new ViewRendererException("Exception rendering json view of " + value + " with descriptor " + viewDescriptor, e);
@@ -94,18 +94,16 @@ public void parse(String json) {
}
try {
//noinspection unchecked
- value = (T) getObjectMapper().readValue(json, viewDescriptor.getBeanClass());
+ value = (T) getJsonMapper().readValue(json, viewDescriptor.getBeanClass());
} catch (IOException e) {
throw new ViewRendererException("Error parsing json to object", e);
}
}
- private ObjectMapper getObjectMapper() {
+ private JsonMapper getJsonMapper() {
if (mapper == null) {
- mapper = new ObjectMapper();
- mapper.enable(SerializationFeature.INDENT_OUTPUT);
- mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
+ mapper = StringPojoParser.createJsonMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(viewDescriptor.getBeanClass(), new JsonViewDescriptorSerializer(viewDescriptor));
//noinspection unchecked
diff --git a/web/pom.xml b/web/pom.xml
index 1decdc7c..5dd2c2bc 100644
--- a/web/pom.xml
+++ b/web/pom.xml
@@ -23,14 +23,14 @@
tools.dynamia.webjar
- 5.4.11
+ 5.4.12A set of common classes and interfaces for web application developmenttools.dynamiatools.dynamia.parent
- 5.4.11
+ 5.4.12DynamiaTools - Web
@@ -88,27 +88,27 @@
tools.dynamiatools.dynamia.commons
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.integration
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.navigation
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.viewers
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.crud
- 5.4.11
+ 5.4.12org.springframework
diff --git a/web/src/main/java/tools/dynamia/web/navigation/RestNavigationController.java b/web/src/main/java/tools/dynamia/web/navigation/RestNavigationController.java
index fe58c604..8d20b16e 100644
--- a/web/src/main/java/tools/dynamia/web/navigation/RestNavigationController.java
+++ b/web/src/main/java/tools/dynamia/web/navigation/RestNavigationController.java
@@ -19,8 +19,6 @@
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
@@ -276,7 +274,7 @@ private ResponseEntity update(String path, Long id, String jsonData, Htt
}
ViewDescriptor descriptor = getJsonFormDescriptor(entityClass, true);
- ObjectMapper mapper = new ObjectMapper();
+ var mapper = StringPojoParser.createJsonMapper();
try {
final ViewDescriptor desc = descriptor;
JsonNode node = mapper.readTree(jsonData);
@@ -338,10 +336,7 @@ public static int getParameterNumber(HttpServletRequest request, String name) {
public static ResponseEntity getMetadata(HttpServletRequest request, ViewDescriptor viewDescriptor) {
if (viewDescriptor != null && request.getParameter("_metadata") != null) {
- ObjectMapper mapper = new ObjectMapper();
- mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
- mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
-
+ var mapper = StringPojoParser.createJsonMapper();
try {
return new ResponseEntity<>(mapper.writeValueAsString(viewDescriptor), HttpStatus.OK);
diff --git a/zk/pom.xml b/zk/pom.xml
index 245107c0..b3c25174 100644
--- a/zk/pom.xml
+++ b/zk/pom.xml
@@ -21,12 +21,12 @@
tools.dynamia.parenttools.dynamia
- 5.4.11
+ 5.4.124.0.0tools.dynamia.zk
- 5.4.11
+ 5.4.12jarDynamiaTools - ZKhttps://dynamia.tools/docs/zk
@@ -99,31 +99,31 @@
tools.dynamiatools.dynamia.web
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.navigation
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.ui
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.domain
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.viewers
- 5.4.11
+ 5.4.12org.yaml
@@ -134,19 +134,19 @@
tools.dynamiatools.dynamia.crud
- 5.4.11
+ 5.4.12tools.dynamiatools.dynamia.reports
- 5.4.11
+ 5.4.12compiletools.dynamiatools.dynamia.templates
- 5.4.11
+ 5.4.12compile
@@ -220,6 +220,12 @@
spring-boot-autoconfigure
+
+ com.google.guava
+ failureaccess
+ 1.0.3
+
+
diff --git a/zk/src/main/java/tools/dynamia/zk/ui/LongOperationMonitorWindow.java b/zk/src/main/java/tools/dynamia/zk/ui/LongOperationMonitorWindow.java
index b1e9797a..33fd4e47 100644
--- a/zk/src/main/java/tools/dynamia/zk/ui/LongOperationMonitorWindow.java
+++ b/zk/src/main/java/tools/dynamia/zk/ui/LongOperationMonitorWindow.java
@@ -17,141 +17,142 @@
package tools.dynamia.zk.ui;
import org.zkoss.zk.ui.event.Events;
-import org.zkoss.zul.Button;
-import org.zkoss.zul.Caption;
-import org.zkoss.zul.Div;
-import org.zkoss.zul.Hlayout;
-import org.zkoss.zul.Label;
-import org.zkoss.zul.Progressmeter;
-import org.zkoss.zul.Vlayout;
-import org.zkoss.zul.Window;
-import tools.dynamia.commons.Callback;
+import org.zkoss.zul.*;
import tools.dynamia.commons.ClassMessages;
+import tools.dynamia.commons.DateTimeUtils;
import tools.dynamia.commons.Messages;
-import tools.dynamia.commons.StopWatch;
import tools.dynamia.commons.logger.LoggingService;
+import tools.dynamia.integration.ProgressEvent;
import tools.dynamia.integration.ProgressMonitor;
+import tools.dynamia.ui.MessageType;
import tools.dynamia.ui.UIMessages;
import tools.dynamia.zk.util.LongOperation;
import tools.dynamia.zk.util.ZKUtil;
-import java.util.function.Consumer;
+import java.util.Date;
public class LongOperationMonitorWindow extends Window {
- /**
- *
- */
- private static final long serialVersionUID = -2630380982547205553L;
- public static final int DEFAULT_REFRESH_RATE = 2000;
+ private static final long serialVersionUID = 1L;
+
private final ClassMessages messages = ClassMessages.get(LongOperationMonitorWindow.class);
private final ProgressMonitor monitor;
+ private final LongOperation longOperation;
private Progressmeter progress;
- private String messageTemplate = messages.get("DefaultProgressMessage");
- private int refreshRate;
- private final LongOperation longOperation;
private Caption titleCaption;
private Label messageLabel;
- public LongOperationMonitorWindow(LongOperation longOperation, ProgressMonitor monitor) {
- this(longOperation, monitor, DEFAULT_REFRESH_RATE);
- }
+ private String messageTemplate = messages.get("DefaultProgressMessage");
+ private Listbox logListbox;
+ private boolean showLog;
- public LongOperationMonitorWindow(LongOperation longOperation, ProgressMonitor monitor, int refreshRate) {
+ public LongOperationMonitorWindow(LongOperation longOperation, ProgressMonitor monitor) {
this.longOperation = longOperation;
this.monitor = monitor;
- this.refreshRate = refreshRate;
initUI();
- initMonitor();
+ bindEventListeners();
setPage(ZKUtil.getFirstPage());
}
- public static LongOperationMonitorWindow show(String title, LongOperation longOperation, ProgressMonitor monitor) {
- return show(title, longOperation, monitor, DEFAULT_REFRESH_RATE);
+ public static LongOperationMonitorWindow show(String title,
+ LongOperation longOperation,
+ ProgressMonitor monitor) {
+ LongOperationMonitorWindow win = new LongOperationMonitorWindow(longOperation, monitor);
+ win.setTitle(title);
+ win.setPosition("center");
+ win.doModal();
+ longOperation.onException(e -> win.detach());
+ return win;
}
- public static LongOperationMonitorWindow show(String title, LongOperation longOperation, ProgressMonitor monitor, int refreshRate) {
- LongOperationMonitorWindow wind = new LongOperationMonitorWindow(longOperation, monitor, refreshRate);
- wind.setTitle(title);
- wind.setPosition("center");
- wind.doModal();
- return wind;
- }
-
- /**
- * Run and show a progress window for a long-running operation
- */
- public static LongOperationMonitorWindow start(String title, Consumer operation, Callback onFinish) {
+ public static LongOperationMonitorWindow start(String title,
+ String finishMessage,
+ java.util.function.Consumer op) {
var monitor = new ProgressMonitor();
- var longOp = LongOperation.create()
- .execute(() -> operation.accept(monitor))
- .onFinish(onFinish);
+ LongOperation longOp = LongOperation.create()
+ .execute(() -> op.accept(monitor))
+ .onFinish(() -> UIMessages.showMessage(finishMessage));
longOp.start();
-
return show(title, longOp, monitor);
}
- /**
- * Run and show a progress window for a long-running operation
- */
- public static LongOperationMonitorWindow start(String title, String finishMessage, Consumer operation) {
- return start(title, operation, () -> UIMessages.showMessage(finishMessage));
- }
-
- private void initMonitor() {
+ private void bindEventListeners() {
if (monitor != null) {
- StopWatch stopWatch = new StopWatch(refreshRate);
- monitor.onProgressChanged(evt -> {
- if ((stopWatch.now() && !monitor.isStopped()) || monitor.getCurrent() >= monitor.getMax()) {
- longOperation.updateUI(() -> {
- progress.setValue(evt.getPercent());
- progress.setTooltiptext(evt.getPercent() + "%");
- messageLabel.setValue(evt.getMessage());
- setTitle(Messages.format(messageTemplate, evt.getCurrent(), evt.getMax(), evt.getPercent()));
- });
+ monitor.onProgressChanged(longOperation::progress);
+ }
+
+ longOperation.onEvent(event -> {
+ switch (event.getType()) {
+ case START -> showStartUI();
+ case PROGRESS -> updateProgress(event.getProgress());
+ case FINISH, CANCEL -> finish();
+ case EXCEPTION -> {
+ UIMessages.showMessageDialog(messages.get("OperationErrorMessage") + ": " + event.getError().getMessage(),
+ messages.get("OperationErrorTitle"), MessageType.ERROR);
+ finish();
}
- });
+ }
+ });
- longOperation.onCleanup(this::finish);
- }
+ // Cleanup on window close → cancel op
+ addEventListener(Events.ON_CLOSE, evt -> {
+ evt.stopPropagation();
+ longOperation.cancel();
+ });
+ }
+ private void showStartUI() {
+ titleCaption.setIconSclass("fa fa-refresh fa-spin fa-2x");
}
- private void finish() {
- if (ZKUtil.isInEventListener()) {
- detach();
- } else {
- longOperation.updateUI(this::detach);
+ private void updateProgress(ProgressEvent evt) {
+ progress.setValue(evt.getPercent());
+ progress.setTooltiptext(evt.getPercent() + "%");
+ messageLabel.setValue(evt.getMessage());
+ if (isShowLog()) {
+ var item = logListbox.appendItem(DateTimeUtils.formatTime(new Date()) + " - " + evt.getMessage(), "");
+ logListbox.scrollToIndex(item.getIndex());
}
+ String title = Messages.format(messageTemplate,
+ evt.getCurrent(), evt.getMax(), evt.getPercent());
+ setTitle(title);
}
- private void initUI() {
+ private void finish() {
+ titleCaption.setIconSclass("fa fa-check");
+ detach(); // UI thread safe — EventQueue guarantees it
+ }
+ private void initUI() {
setWidth("500px");
setClosable(true);
- setStyle("padding: 10px");
+ setStyle("padding:10px");
+
titleCaption = new Caption("");
- titleCaption.setIconSclass("fa fa-refresh fa-spin fa-2x");
titleCaption.setParent(this);
Vlayout layout = new Vlayout();
layout.setHflex("1");
layout.setParent(this);
+ logListbox = new Listbox();
+ logListbox.setVisible(false);
+ logListbox.setHeight("150px");
+ logListbox.setParent(layout);
+
progress = new Progressmeter();
progress.setHflex("2");
- progress.setParent(layout);
progress.setValue(0);
+ progress.setParent(layout);
- Div messageContainer = new Div();
- messageContainer.setStyle("text-align: center");
+ Div msg = new Div();
+ msg.setStyle("text-align:center");
messageLabel = new Label();
- messageLabel.setParent(messageContainer);
- messageContainer.setParent(layout);
-
+ messageLabel.setParent(msg);
+ msg.setParent(layout);
Hlayout hlayout = new Hlayout();
hlayout.setHflex("1");
@@ -179,37 +180,33 @@ private void initUI() {
}
- private void stop() {
+ protected void stop() {
try {
longOperation.onFinish(null);
monitor.stop();
} catch (Exception e) {
- LoggingService.get(getClass()).error("Error stopping long operation", e);
+ LoggingService.get(LongOperationMonitorWindow.class).error("Error stopping long operation", e);
} finally {
finish();
}
}
- public String getMessageTemplate() {
- return messageTemplate;
+ @Override
+ public void setTitle(String title) {
+ titleCaption.setLabel(title);
}
public void setMessageTemplate(String messageTemplate) {
this.messageTemplate = messageTemplate;
}
- public int getRefreshRate() {
- return refreshRate;
- }
-
- public void setRefreshRate(int refreshRate) {
- this.refreshRate = refreshRate;
+ public boolean isShowLog() {
+ return showLog;
}
- @Override
- public void setTitle(String title) {
- titleCaption.setLabel(title);
+ public void setShowLog(boolean showLog) {
+ this.showLog = showLog;
+ logListbox.setVisible(showLog);
}
-
}
diff --git a/zk/src/main/java/tools/dynamia/zk/util/LongOperation.java b/zk/src/main/java/tools/dynamia/zk/util/LongOperation.java
index aad1385b..5e5c1b60 100644
--- a/zk/src/main/java/tools/dynamia/zk/util/LongOperation.java
+++ b/zk/src/main/java/tools/dynamia/zk/util/LongOperation.java
@@ -16,245 +16,296 @@
*/
package tools.dynamia.zk.util;
-import org.springframework.core.task.TaskExecutor;
-import org.zkoss.zk.ui.Desktop;
-import org.zkoss.zk.ui.DesktopUnavailableException;
-import org.zkoss.zk.ui.Executions;
-import org.zkoss.zk.ui.Sessions;
-import org.zkoss.zk.ui.WebApps;
-import org.zkoss.zk.ui.sys.DesktopCache;
-import org.zkoss.zk.ui.sys.DesktopCtrl;
-import org.zkoss.zk.ui.sys.WebAppCtrl;
+import org.zkoss.zk.ui.event.Event;
+import org.zkoss.zk.ui.event.EventListener;
+import org.zkoss.zk.ui.event.EventQueue;
+import org.zkoss.zk.ui.event.EventQueues;
import tools.dynamia.commons.Callback;
import tools.dynamia.commons.logger.LoggingService;
+import tools.dynamia.integration.ProgressEvent;
+import tools.dynamia.integration.scheduling.SchedulerUtil;
+import java.util.ArrayList;
+import java.util.List;
import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
+/**
+ * Executes a long-running operation asynchronously while safely notifying
+ * the UI through a session-scoped EventQueue.
+ *
+ * This class provides callback hooks for start, execution, finish,
+ * cancel, cleanup and exception handling without requiring
+ * manual server push or desktop activation.
+ *
+ *