This is an automated email from the ASF dual-hosted git repository.

zihaoxiang pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git


The following commit(s) were added to refs/heads/dev by this push:
     new dddf2dc834 [Fix-16914] [Task] ParameterUtils will throw exception when 
the input contains '$[xx]' (#16916)
dddf2dc834 is described below

commit dddf2dc83428e4bb5eb7e1286a5b5f53d5dbaf8b
Author: Wenjun Ruan <[email protected]>
AuthorDate: Tue Dec 24 17:05:38 2024 +0800

    [Fix-16914] [Task] ParameterUtils will throw exception when the input 
contains '$[xx]' (#16916)
---
 .../task/api/parser/PropertyPlaceholderHelper.java |   2 +-
 .../task/api/parser/TimePlaceholderUtils.java      | 146 ++++++---------------
 .../plugin/task/api/utils/ParameterUtils.java      |  21 +--
 .../task/api/parser/TimePlaceholderUtilsTest.java  |   9 +-
 .../plugin/task/api/utils/ParameterUtilsTest.java  |  47 +++----
 5 files changed, 78 insertions(+), 147 deletions(-)

diff --git 
a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parser/PropertyPlaceholderHelper.java
 
b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parser/PropertyPlaceholderHelper.java
index e10657d084..dbf484fc05 100644
--- 
a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parser/PropertyPlaceholderHelper.java
+++ 
b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parser/PropertyPlaceholderHelper.java
@@ -119,7 +119,7 @@ public class PropertyPlaceholderHelper {
      */
     public String replacePlaceholders(String value, PlaceholderResolver 
placeholderResolver) {
         notNull(value, "'value' must not be null");
-        return parseStringValue(value, placeholderResolver, new 
HashSet<String>());
+        return parseStringValue(value, placeholderResolver, new HashSet<>());
     }
 
     protected String parseStringValue(
diff --git 
a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parser/TimePlaceholderUtils.java
 
b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parser/TimePlaceholderUtils.java
index 42d95083f1..24bb791870 100644
--- 
a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parser/TimePlaceholderUtils.java
+++ 
b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parser/TimePlaceholderUtils.java
@@ -71,44 +71,6 @@ import lombok.extern.slf4j.Slf4j;
 @Slf4j
 public class TimePlaceholderUtils {
 
-    /**
-     * Prefix of the position to be replaced
-     */
-    public static final String PLACEHOLDER_PREFIX = "$[";
-
-    /**
-     * The suffix of the position to be replaced
-     */
-    public static final String PLACEHOLDER_SUFFIX = "]";
-
-    /**
-     * Replaces all placeholders of format {@code ${name}} with the value 
returned
-     * from the supplied {@link PropertyPlaceholderHelper.PlaceholderResolver}.
-     *
-     * @param value                          the value containing the 
placeholders to be replaced
-     * @param date                           custom date
-     * @param ignoreUnresolvablePlaceholders ignore unresolvable placeholders
-     * @return the supplied value with placeholders replaced inline
-     */
-    public static String replacePlaceholders(String value, Date date, boolean 
ignoreUnresolvablePlaceholders) {
-        PropertyPlaceholderHelper strictHelper = 
getPropertyPlaceholderHelper(false);
-        PropertyPlaceholderHelper nonStrictHelper = 
getPropertyPlaceholderHelper(true);
-
-        PropertyPlaceholderHelper helper = (ignoreUnresolvablePlaceholders ? 
nonStrictHelper : strictHelper);
-        return helper.replacePlaceholders(value, new 
TimePlaceholderResolver(value, date));
-    }
-
-    /**
-     * Creates a new {@code PropertyPlaceholderHelper} that uses the supplied 
prefix and suffix.
-     *
-     * @param ignoreUnresolvablePlaceholders indicates whether unresolvable 
placeholders should
-     *                                       be ignored ({@code true}) or 
cause an exception ({@code false})
-     */
-    private static PropertyPlaceholderHelper 
getPropertyPlaceholderHelper(boolean ignoreUnresolvablePlaceholders) {
-        return new PropertyPlaceholderHelper(PLACEHOLDER_PREFIX, 
PLACEHOLDER_SUFFIX, null,
-                ignoreUnresolvablePlaceholders);
-    }
-
     /**
      * calculate expression's value
      *
@@ -303,79 +265,35 @@ public class TimePlaceholderUtils {
     }
 
     /**
-     * Placeholder replacement resolver
-     */
-    private static class TimePlaceholderResolver
-            implements
-                PropertyPlaceholderHelper.PlaceholderResolver {
-
-        private final String value;
-
-        private final Date date;
-
-        public TimePlaceholderResolver(String value, Date date) {
-            this.value = value;
-            this.date = date;
-        }
-
-        @Override
-        public String resolvePlaceholder(String placeholderName) {
-            try {
-                return calculateTime(placeholderName, date);
-            } catch (Exception ex) {
-                log.error("resolve placeholder '{}' in [ {} ]", 
placeholderName, value, ex);
-                return null;
-            }
-        }
-    }
-
-    /**
-     * return the formatted date according to the corresponding date format
-     *
-     * @param expression date expression
-     * @param date       date
-     * @return reformat date
-     */
-    public static String getPlaceHolderTime(String expression, Date date) {
-        if (StringUtils.isBlank(expression)) {
-            throw new IllegalArgumentException("expression is null");
-        }
-        if (null == date) {
-            throw new IllegalArgumentException("date is null");
-        }
-        return calculateTime(expression, date);
-    }
-
-    /**
-     * calculate time
+     * Format time expression with given date, the date cannot be null.
+     * <p> If the expression is not a time expression, return the original 
expression.
      *
-     * @param date date
-     * @return calculate time
      */
-    private static String calculateTime(String expression, Date date) {
+    public static String formatTimeExpression(final String timeExpression, 
final Date date,
+                                              final boolean 
ignoreInvalidExpression) {
         // After N years: $[add_months(yyyyMMdd,12*N)], the first N months: 
$[add_months(yyyyMMdd,-N)], etc
         if (date == null) {
-            throw new IllegalArgumentException("Cannot parse the expression: " 
+ expression + ", date is null");
+            throw new IllegalArgumentException("Cannot parse the expression: " 
+ timeExpression + ", date is null");
+        }
+        if (StringUtils.isEmpty(timeExpression)) {
+            if (ignoreInvalidExpression) {
+                return timeExpression;
+            }
+            throw new IllegalArgumentException("Cannot format the date" + date 
+ " with null timeExpression");
         }
         try {
-            if (expression.startsWith(TIMESTAMP)) {
-                String timeExpression = 
expression.substring(TIMESTAMP.length() + 1, expression.length() - 1);
-
-                Map.Entry<Date, String> entry = 
calcTimeExpression(timeExpression, date);
-
-                String dateStr = DateUtils.format(entry.getKey(), 
entry.getValue());
-
-                Date timestamp = DateUtils.parse(dateStr, 
PARAMETER_FORMAT_TIME);
-
-                return String.valueOf(timestamp.getTime() / 1000);
+            if (timeExpression.startsWith(TIMESTAMP)) {
+                return calculateTimeStamp(timeExpression, date);
             }
-            if (expression.startsWith(YEAR_WEEK)) {
-                return calculateYearWeek(expression, date);
+            if (timeExpression.startsWith(YEAR_WEEK)) {
+                return calculateYearWeek(timeExpression, date);
             }
-            Map.Entry<Date, String> entry = calcTimeExpression(expression, 
date);
-            return DateUtils.format(entry.getKey(), entry.getValue());
+            return calcTimeExpression(timeExpression, date);
         } catch (Exception e) {
-            throw new IllegalArgumentException("Unsupported placeholder 
expression: " + expression, e);
+            if (ignoreInvalidExpression) {
+                return timeExpression;
+            }
+            throw new IllegalArgumentException("Unsupported placeholder 
expression: " + timeExpression, e);
         }
     }
 
@@ -385,7 +303,7 @@ public class TimePlaceholderUtils {
      * @param date       date
      * @return week of year
      */
-    public static String calculateYearWeek(String expression, Date date) {
+    private static String calculateYearWeek(final String expression, final 
Date date) {
 
         String dataFormat = expression.substring(YEAR_WEEK.length() + 1, 
expression.length() - 1);
 
@@ -465,6 +383,19 @@ public class TimePlaceholderUtils {
         return weekYearStr;
     }
 
+    private static String calculateTimeStamp(final String expression, final 
Date date) {
+        final String timeExpression = expression.substring(TIMESTAMP.length() 
+ 1, expression.length() - 1);
+        final String calculatedTimeExpression = 
calcTimeExpression(timeExpression, date);
+        if (StringUtils.equals(expression, calculatedTimeExpression)) {
+            return expression;
+        }
+        final Date timestamp = DateUtils.parse(calculatedTimeExpression, 
PARAMETER_FORMAT_TIME);
+        if (timestamp == null) {
+            throw new IllegalArgumentException("Cannot parse the expression: " 
+ expression + " with date: " + date);
+        }
+        return String.valueOf(timestamp.getTime() / 1000);
+    }
+
     /**
      * calculate time expresstion
      *
@@ -472,8 +403,8 @@ public class TimePlaceholderUtils {
      * @param date       date
      * @return map with date, date format
      */
-    public static Map.Entry<Date, String> calcTimeExpression(String 
expression, Date date) {
-        Map.Entry<Date, String> resultEntry;
+    private static String calcTimeExpression(final String expression, final 
Date date) {
+        final Map.Entry<Date, String> resultEntry;
 
         if (expression.startsWith(ADD_MONTHS)) {
             resultEntry = calcMonths(expression, date);
@@ -500,8 +431,9 @@ public class TimePlaceholderUtils {
         } else {
             resultEntry = calcMinutes(expression, date);
         }
-
-        return resultEntry;
+        final Date finalDate = resultEntry.getKey();
+        final String finalFormat = resultEntry.getValue();
+        return DateUtils.format(finalDate, finalFormat);
     }
 
     /**
diff --git 
a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/utils/ParameterUtils.java
 
b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/utils/ParameterUtils.java
index 9733453b2d..9a7b9a86eb 100644
--- 
a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/utils/ParameterUtils.java
+++ 
b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/utils/ParameterUtils.java
@@ -49,8 +49,6 @@ public class ParameterUtils {
 
     private static final Pattern DATE_PARSE_PATTERN = 
Pattern.compile("\\$\\[([^\\$\\]]+)]");
 
-    private static final Pattern DATE_START_PATTERN = 
Pattern.compile("^[0-9]");
-
     private static final char PARAM_REPLACE_CHAR = '?';
 
     private ParameterUtils() {
@@ -288,21 +286,24 @@ public class ParameterUtils {
         return map;
     }
 
-    private static String dateTemplateParse(String templateStr, Date date) {
-        if (templateStr == null) {
-            return null;
+    // Replace the time placeholder in the template string with the given 
actual time value
+    // If the templateStr does not contain a time placeholder, will return the 
original string
+    private static String dateTemplateParse(final String templateStr, final 
Date date) {
+        if (StringUtils.isEmpty(templateStr)) {
+            return templateStr;
         }
 
-        StringBuffer newValue = new StringBuffer(templateStr.length());
+        final StringBuffer newValue = new StringBuffer(templateStr.length());
 
-        Matcher matcher = DATE_PARSE_PATTERN.matcher(templateStr);
+        final Matcher matcher = DATE_PARSE_PATTERN.matcher(templateStr);
 
         while (matcher.find()) {
-            String key = matcher.group(1);
-            if (DATE_START_PATTERN.matcher(key).matches()) {
+            final String key = matcher.group(1);
+            String value = TimePlaceholderUtils.formatTimeExpression(key, 
date, true);
+            if (StringUtils.equals(key, value)) {
+                // There is no corresponding time format, so the original 
string is retained
                 continue;
             }
-            String value = TimePlaceholderUtils.getPlaceHolderTime(key, date);
             matcher.appendReplacement(newValue, value);
         }
 
diff --git 
a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/test/java/org/apache/dolphinscheduler/plugin/task/api/parser/TimePlaceholderUtilsTest.java
 
b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/test/java/org/apache/dolphinscheduler/plugin/task/api/parser/TimePlaceholderUtilsTest.java
index b1b992e857..86d69a03c7 100644
--- 
a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/test/java/org/apache/dolphinscheduler/plugin/task/api/parser/TimePlaceholderUtilsTest.java
+++ 
b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/test/java/org/apache/dolphinscheduler/plugin/task/api/parser/TimePlaceholderUtilsTest.java
@@ -27,7 +27,6 @@ import 
org.apache.dolphinscheduler.plugin.task.api.utils.ParameterUtils;
 import java.util.Date;
 import java.util.Map;
 
-import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
 public class TimePlaceholderUtilsTest {
@@ -131,10 +130,8 @@ public class TimePlaceholderUtilsTest {
     }
 
     @Test
-    void getPlaceHolderTime() {
-        IllegalArgumentException illegalArgumentException = 
Assertions.assertThrows(IllegalArgumentException.class,
-                () -> 
TimePlaceholderUtils.getPlaceHolderTime("$[week_last_day(yyyy-MM-dd,0) - 1]", 
new Date()));
-        assertEquals("Unsupported placeholder expression: 
$[week_last_day(yyyy-MM-dd,0) - 1]",
-                illegalArgumentException.getMessage());
+    void formatTimeExpressionWithInvalidExpression() {
+        assertEquals("$[week_last_day(yyyy-MM-dd,0) - 1]",
+                
TimePlaceholderUtils.formatTimeExpression("$[week_last_day(yyyy-MM-dd,0) - 1]", 
new Date(), true));
     }
 }
diff --git 
a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/test/java/org/apache/dolphinscheduler/plugin/task/api/utils/ParameterUtilsTest.java
 
b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/test/java/org/apache/dolphinscheduler/plugin/task/api/utils/ParameterUtilsTest.java
index 1c0dbc7c06..6a25c573a7 100644
--- 
a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/test/java/org/apache/dolphinscheduler/plugin/task/api/utils/ParameterUtilsTest.java
+++ 
b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/test/java/org/apache/dolphinscheduler/plugin/task/api/utils/ParameterUtilsTest.java
@@ -17,18 +17,16 @@
 
 package org.apache.dolphinscheduler.plugin.task.api.utils;
 
-import static 
org.apache.dolphinscheduler.plugin.task.api.parser.TimePlaceholderUtils.replacePlaceholders;
+import static 
org.apache.dolphinscheduler.plugin.task.api.parser.PlaceholderUtils.replacePlaceholders;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import org.apache.dolphinscheduler.common.constants.DateConstants;
-import org.apache.dolphinscheduler.common.utils.DateUtils;
 import org.apache.dolphinscheduler.common.utils.JSONUtils;
 import org.apache.dolphinscheduler.plugin.task.api.enums.DataType;
 import org.apache.dolphinscheduler.plugin.task.api.enums.Direct;
 import org.apache.dolphinscheduler.plugin.task.api.model.Property;
-import org.apache.dolphinscheduler.plugin.task.api.parser.PlaceholderUtils;
 
 import java.text.ParseException;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -51,8 +49,8 @@ public class ParameterUtilsTest {
                 JSONUtils.toJsonString(Lists.newArrayList(3.1415, 2.44, 
3.44))));
         String sql = ParameterUtils.expandListParameter(params,
                 "select * from test where col1 in ('${col1}') and 
date='${date}' and col2 in ('${col2}')");
-        Assertions.assertEquals("select * from test where col1 in (?,?,?) and 
date=? and col2 in (?,?,?)", sql);
-        Assertions.assertEquals(7, params.size());
+        assertEquals("select * from test where col1 in (?,?,?) and date=? and 
col2 in (?,?,?)", sql);
+        assertEquals(7, params.size());
 
         Map<Integer, Property> params2 = new HashMap<>();
         params2.put(1,
@@ -60,8 +58,8 @@ public class ParameterUtilsTest {
         params2.put(2, new Property("date", Direct.IN, DataType.DATE, 
"2020-06-30"));
         String sql2 = ParameterUtils.expandListParameter(params2,
                 "select * from test where col1 in ('${col}') and 
date='${date}'");
-        Assertions.assertEquals("select * from test where col1 in (?) and 
date=?", sql2);
-        Assertions.assertEquals(2, params2.size());
+        assertEquals("select * from test where col1 in (?) and date=?", sql2);
+        assertEquals(2, params2.size());
 
     }
 
@@ -77,21 +75,14 @@ public class ParameterUtilsTest {
 
         // parameterString、parameterMap is not null
         String parameterString = "test_parameter";
-        Assertions.assertEquals(parameterString,
+        assertEquals(parameterString,
                 ParameterUtils.convertParameterPlaceholders(parameterString, 
parameterMap));
 
         // replace variable ${} form
         parameterMap.put("testParameter2", "${testParameter}");
-        Assertions.assertEquals(parameterString,
-                PlaceholderUtils.replacePlaceholders(parameterString, 
parameterMap, true));
+        assertEquals(parameterString,
+                replacePlaceholders(parameterString, parameterMap, true));
 
-        // replace time $[...] form, eg. $[yyyyMMdd]
-        Date cronTime = new Date();
-        Assertions.assertEquals(parameterString, 
replacePlaceholders(parameterString, cronTime, true));
-
-        // replace time $[...] form, eg. $[yyyyMMdd]
-        Date cronTimeStr = DateUtils.stringToDate("2019-02-02 00:00:00");
-        Assertions.assertEquals(parameterString, 
replacePlaceholders(parameterString, cronTimeStr, true));
     }
 
     @Test
@@ -103,20 +94,30 @@ public class ParameterUtilsTest {
         parameterMap.put("user", "Kris");
         parameterMap.put(DateConstants.PARAMETER_DATETIME, "20201201123000");
         parameterString = 
ParameterUtils.convertParameterPlaceholders(parameterString, parameterMap);
-        Assertions.assertEquals(
+        assertEquals(
                 "Kris is userName, '$[1]' '20221201' '20181201' '20210301' 
'20200801' '20201215' '20201117'  '20201204'  '$[0]' '20201128' '143000' 
'113000' '123300' '122800'  '$[3]'",
                 parameterString);
     }
 
+    @Test
+    public void convertParameterPlaceholdersWithPunct() {
+        final String sql = "get_json_object(json_array, '$[*].pageId')";
+        final Map<String, String> paramsMap = new HashMap<>();
+        paramsMap.put("key", "value");
+
+        assertEquals("get_json_object(json_array, '$[*].pageId')",
+                ParameterUtils.convertParameterPlaceholders(sql, paramsMap));
+    }
+
     /**
      * Test handleEscapes
      */
     @Test
-    public void testHandleEscapes() throws Exception {
+    public void testHandleEscapes() {
         Assertions.assertNull(ParameterUtils.handleEscapes(null));
-        Assertions.assertEquals("", ParameterUtils.handleEscapes(""));
-        Assertions.assertEquals("test Parameter", 
ParameterUtils.handleEscapes("test Parameter"));
-        Assertions.assertEquals("////%test////%Parameter", 
ParameterUtils.handleEscapes("%test%Parameter"));
+        assertEquals("", ParameterUtils.handleEscapes(""));
+        assertEquals("test Parameter", ParameterUtils.handleEscapes("test 
Parameter"));
+        assertEquals("////%test////%Parameter", 
ParameterUtils.handleEscapes("%test%Parameter"));
     }
 
 }

Reply via email to