This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
commit 7423d2053e3660adb20d5e5702e98555b3b31e19 Author: Claus Ibsen <[email protected]> AuthorDate: Tue Sep 29 09:14:01 2026 +0200 camel-catalog - Validate durations with TimeUtils, the same parsing as the runtime The catalog kept its own copy of the old time pattern parser, so it rejected durations the runtime accepts (1d, 500ms, 1h 30m) and differed on edge cases. Validate with TimeUtils.toDuration, deprecate the catalog TimePatternConverter as a delegate to TimeUtils, and switch the camel-jbang since options to TimeUtils. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> Signed-off-by: Claus Ibsen <[email protected]> --- .../org/apache/camel/catalog/CamelCatalogTest.java | 9 +- .../camel/catalog/impl/AbstractCamelCatalog.java | 28 ++----- .../camel/catalog/impl/TimePatternConverter.java | 96 ++-------------------- .../jbang/core/commands/action/CamelLogAction.java | 6 +- .../core/commands/action/CamelReceiveAction.java | 5 +- .../core/commands/action/CamelTraceAction.java | 5 +- 6 files changed, 29 insertions(+), 120 deletions(-) diff --git a/catalog/camel-catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java b/catalog/camel-catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java index 385601dd797d..e5bba5ad9f28 100644 --- a/catalog/camel-catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java +++ b/catalog/camel-catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java @@ -1090,7 +1090,14 @@ public class CamelCatalogTest { assertTrue(catalog.validateTimePattern("1h")); assertTrue(catalog.validateTimePattern("1hour")); assertTrue(catalog.validateTimePattern("2hours")); - + // the same patterns as the runtime accepts + assertTrue(catalog.validateTimePattern("1d")); + assertTrue(catalog.validateTimePattern("500ms")); + assertTrue(catalog.validateTimePattern("1h 30m")); + assertTrue(catalog.validateTimePattern("PT5S")); + + assertFalse(catalog.validateTimePattern("")); + assertFalse(catalog.validateTimePattern("5x")); assertFalse(catalog.validateTimePattern("bla")); assertFalse(catalog.validateTimePattern("2year")); assertFalse(catalog.validateTimePattern("60darn")); diff --git a/core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/AbstractCamelCatalog.java b/core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/AbstractCamelCatalog.java index 5887612ab968..eecb0dcc4cb4 100644 --- a/core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/AbstractCamelCatalog.java +++ b/core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/AbstractCamelCatalog.java @@ -22,7 +22,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URI; import java.net.URISyntaxException; -import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -64,6 +63,7 @@ import org.apache.camel.tooling.model.TransformerModel; import org.apache.camel.util.ObjectHelper; import org.apache.camel.util.ReflectionHelper; import org.apache.camel.util.StringHelper; +import org.apache.camel.util.TimeUtils; import org.apache.camel.util.URISupport; import static org.apache.camel.util.StringHelper.isDashed; @@ -1836,28 +1836,16 @@ public abstract class AbstractCamelCatalog { } private static boolean validateDuration(String value) { - boolean valid = false; + if (value == null || value.isBlank()) { + return false; + } try { - Long.parseLong(value); - valid = true; + // same parsing as the runtime: a number of millis, a time pattern such as 5s or 1h30m, or ISO-8601 (PT5S) + TimeUtils.toDuration(value); + return true; } catch (Exception e) { - // ignore - } - if (!valid) { - try { - if (value.startsWith("P") || value.startsWith("-P") || value.startsWith("p") || value.startsWith("-p")) { - // its a duration - Duration.parse(value); - } else { - // it may be a time pattern, such as 5s for 5 seconds = 5000 - TimePatternConverter.toMilliSeconds(value); - } - valid = true; - } catch (Exception e) { - // ignore - } + return false; } - return valid; } private static String stripOptionalPrefixFromName(Map<String, BaseOptionModel> rows, String name) { diff --git a/core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/TimePatternConverter.java b/core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/TimePatternConverter.java index 420960baf3a0..801f3ace1c8d 100644 --- a/core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/TimePatternConverter.java +++ b/core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/TimePatternConverter.java @@ -16,19 +16,15 @@ */ package org.apache.camel.catalog.impl; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import org.apache.camel.util.TimeUtils; /** - * This class is a copy from camel-core so we can use it independent to validate uris with time patterns + * Converts a time pattern such as 5s or 1h30m to milliseconds. + * + * @deprecated use {@link TimeUtils#toMilliSeconds(String)} which is the same parsing as the runtime */ +@Deprecated(since = "4.23.0") public final class TimePatternConverter { - private static final Pattern NUMBERS_ONLY_STRING_PATTERN = Pattern.compile("^[-]?(\\d)+$", Pattern.CASE_INSENSITIVE); - private static final Pattern HOUR_REGEX_PATTERN = Pattern.compile("((\\d)*(\\d))h(our(s)?)?", Pattern.CASE_INSENSITIVE); - private static final Pattern MINUTES_REGEX_PATTERN - = Pattern.compile("((\\d)*(\\d))m(in(ute(s)?)?)?", Pattern.CASE_INSENSITIVE); - private static final Pattern SECONDS_REGEX_PATTERN - = Pattern.compile("((\\d)*(\\d))s(ec(ond)?(s)?)?", Pattern.CASE_INSENSITIVE); /** * Utility classes should not have a public constructor. @@ -37,86 +33,6 @@ public final class TimePatternConverter { } public static long toMilliSeconds(String source) throws IllegalArgumentException { - long milliseconds = 0; - boolean foundFlag = false; - - checkCorrectnessOfPattern(source); - Matcher matcher; - - matcher = createMatcher(NUMBERS_ONLY_STRING_PATTERN, source); - if (matcher.find()) { - // Note: This will also be used for regular numeric strings. - // This String -> long converter will be used for all strings. - milliseconds = Long.parseLong(source); - } else { - matcher = createMatcher(HOUR_REGEX_PATTERN, source); - if (matcher.find()) { - milliseconds = milliseconds + (3600000 * Long.parseLong(matcher.group(1))); - foundFlag = true; - } - - matcher = createMatcher(MINUTES_REGEX_PATTERN, source); - if (matcher.find()) { - long minutes = Long.parseLong(matcher.group(1)); - if (minutes > 59 && foundFlag) { - throw new IllegalArgumentException("Minutes should contain a valid value between 0 and 59: " + source); - } - foundFlag = true; - milliseconds = milliseconds + (60000 * minutes); - } - - matcher = createMatcher(SECONDS_REGEX_PATTERN, source); - if (matcher.find()) { - long seconds = Long.parseLong(matcher.group(1)); - if (seconds > 59 && foundFlag) { - throw new IllegalArgumentException("Seconds should contain a valid value between 0 and 59: " + source); - } - foundFlag = true; - milliseconds = milliseconds + (1000 * seconds); - } - - // No pattern matched... initiating fallback check and conversion (if required). - // The source at this point may contain illegal values or special characters - if (!foundFlag) { - milliseconds = Long.parseLong(source); - } - } - - return milliseconds; - } - - private static void checkCorrectnessOfPattern(String source) { - //replace only numbers once - Matcher matcher = createMatcher(NUMBERS_ONLY_STRING_PATTERN, source); - String replaceSource = matcher.replaceFirst(""); - - //replace hour string once - matcher = createMatcher(HOUR_REGEX_PATTERN, replaceSource); - if (matcher.find() && matcher.find()) { - throw new IllegalArgumentException("Hours should not be specified more then once: " + source); - } - replaceSource = matcher.replaceFirst(""); - - //replace minutes once - matcher = createMatcher(MINUTES_REGEX_PATTERN, replaceSource); - if (matcher.find() && matcher.find()) { - throw new IllegalArgumentException("Minutes should not be specified more then once: " + source); - } - replaceSource = matcher.replaceFirst(""); - - //replace seconds once - matcher = createMatcher(SECONDS_REGEX_PATTERN, replaceSource); - if (matcher.find() && matcher.find()) { - throw new IllegalArgumentException("Seconds should not be specified more then once: " + source); - } - replaceSource = matcher.replaceFirst(""); - - if (!replaceSource.isEmpty()) { - throw new IllegalArgumentException("Illegal characters: " + source); - } - } - - private static Matcher createMatcher(Pattern pattern, String source) { - return pattern.matcher(source); + return TimeUtils.toMilliSeconds(source); } } diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLogAction.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLogAction.java index 07953aaf14f1..52c59799c3d8 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLogAction.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLogAction.java @@ -37,7 +37,6 @@ import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Pattern; -import org.apache.camel.catalog.impl.TimePatternConverter; import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; import org.apache.camel.dsl.jbang.core.commands.CommandHelper; import org.apache.camel.dsl.jbang.core.common.CommandLineHelper; @@ -45,6 +44,7 @@ import org.apache.camel.dsl.jbang.core.common.EnvironmentHelper; import org.apache.camel.dsl.jbang.core.common.ProcessHelper; import org.apache.camel.util.StopWatch; import org.apache.camel.util.StringHelper; +import org.apache.camel.util.TimeUtils; import org.apache.camel.util.json.JsonObject; import org.jline.jansi.Ansi; import org.jline.jansi.AnsiConsole; @@ -157,9 +157,9 @@ public class CamelLogAction extends ActionBaseCommand { long millis; if (StringHelper.isDigit(since)) { // is in seconds by default - millis = TimePatternConverter.toMilliSeconds(since) * 1000; + millis = TimeUtils.toMilliSeconds(since) * 1000; } else { - millis = TimePatternConverter.toMilliSeconds(since); + millis = TimeUtils.toMilliSeconds(since); } limit = new Date(System.currentTimeMillis() - millis); } diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelReceiveAction.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelReceiveAction.java index 57d5c16708cc..8541015558d4 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelReceiveAction.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelReceiveAction.java @@ -42,7 +42,6 @@ import com.github.freva.asciitable.AsciiTable; import com.github.freva.asciitable.Column; import com.github.freva.asciitable.HorizontalAlign; import com.github.freva.asciitable.OverflowBehaviour; -import org.apache.camel.catalog.impl.TimePatternConverter; import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; import org.apache.camel.dsl.jbang.core.commands.CommandHelper; import org.apache.camel.dsl.jbang.core.commands.MavenResolverMixin; @@ -543,9 +542,9 @@ public class CamelReceiveAction extends ActionBaseCommand { long millis; if (StringHelper.isDigit(since)) { // is in seconds by default - millis = TimePatternConverter.toMilliSeconds(since) * 1000; + millis = TimeUtils.toMilliSeconds(since) * 1000; } else { - millis = TimePatternConverter.toMilliSeconds(since); + millis = TimeUtils.toMilliSeconds(since); } limit = new Date(System.currentTimeMillis() - millis); } diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelTraceAction.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelTraceAction.java index 0c90cc4573c3..7af7bd991a8f 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelTraceAction.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelTraceAction.java @@ -41,7 +41,6 @@ import com.github.freva.asciitable.AsciiTable; import com.github.freva.asciitable.Column; import com.github.freva.asciitable.HorizontalAlign; import com.github.freva.asciitable.OverflowBehaviour; -import org.apache.camel.catalog.impl.TimePatternConverter; import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; import org.apache.camel.dsl.jbang.core.commands.CommandHelper; import org.apache.camel.dsl.jbang.core.common.PidNameAgeCompletionCandidates; @@ -362,9 +361,9 @@ public class CamelTraceAction extends ActionBaseCommand { long millis; if (StringHelper.isDigit(since)) { // is in seconds by default - millis = TimePatternConverter.toMilliSeconds(since) * 1000; + millis = TimeUtils.toMilliSeconds(since) * 1000; } else { - millis = TimePatternConverter.toMilliSeconds(since); + millis = TimeUtils.toMilliSeconds(since); } limit = new Date(System.currentTimeMillis() - millis); }
