Merge pull request #10582 from thingsboard/tbel_endoceUri_Java_mdn

tbel_encodeDecodeUri_java_as_mdn
This commit is contained in:
Andrew Shvayka 2024-04-17 13:30:46 +03:00 committed by GitHub
commit 963624e2d2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 75 additions and 28 deletions

View File

@ -16,6 +16,7 @@
package org.thingsboard.script.api.tbel;
import com.google.common.primitives.Bytes;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.mvel2.ExecutionContext;
import org.mvel2.ParserConfiguration;
@ -29,32 +30,49 @@ import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAccessor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
@Slf4j
public class TbUtils {
private static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
private static final LinkedHashMap<String, String> mdnEncodingReplacements = new LinkedHashMap<>();
static {
mdnEncodingReplacements.put("\\+", "%20");
mdnEncodingReplacements.put("%21", "!");
mdnEncodingReplacements.put("%27", "'");
mdnEncodingReplacements.put("%28", "\\(");
mdnEncodingReplacements.put("%29", "\\)");
mdnEncodingReplacements.put("%7E", "~");
mdnEncodingReplacements.put("%3B", ";");
mdnEncodingReplacements.put("%2C", ",");
mdnEncodingReplacements.put("%2F", "/");
mdnEncodingReplacements.put("%3F", "\\?");
mdnEncodingReplacements.put("%3A", ":");
mdnEncodingReplacements.put("%40", "@");
mdnEncodingReplacements.put("%26", "&");
mdnEncodingReplacements.put("%3D", "=");
mdnEncodingReplacements.put("%2B", "\\+");
mdnEncodingReplacements.put("%24", Matcher.quoteReplacement("$"));
mdnEncodingReplacements.put("%23", "#");
}
public static void register(ParserConfiguration parserConfig) throws Exception {
parserConfig.addImport("btoa", new MethodStub(TbUtils.class.getMethod("btoa",
String.class)));
@ -175,6 +193,10 @@ public class TbUtils {
ExecutionContext.class, Map.class, List.class)));
parserConfig.addImport("toFlatMap", new MethodStub(TbUtils.class.getMethod("toFlatMap",
ExecutionContext.class, Map.class, List.class, boolean.class)));
parserConfig.addImport("encodeURI", new MethodStub(TbUtils.class.getMethod("encodeURI",
String.class)));
parserConfig.addImport("decodeURI", new MethodStub(TbUtils.class.getMethod("decodeURI",
String.class)));
}
public static String btoa(String input) {
@ -589,22 +611,6 @@ public class TbUtils {
return BigDecimal.valueOf(value).setScale(precision, RoundingMode.HALF_UP).floatValue();
}
private static boolean isHexadecimal(String value) {
return value != null && (value.contains("0x") || value.contains("0X"));
}
private static String prepareNumberString(String value) {
if (value != null) {
value = value.trim();
if (isHexadecimal(value)) {
value = value.replace("0x", "");
value = value.replace("0X", "");
}
value = value.replace(",", ".");
}
return value;
}
public static ExecutionHashMap<String, Object> toFlatMap(ExecutionContext ctx, Map<String, Object> json) {
return toFlatMap(ctx, json, new ArrayList<>(), true);
}
@ -623,6 +629,24 @@ public class TbUtils {
return map;
}
public static String encodeURI(String uri) {
String encoded = URLEncoder.encode(uri, StandardCharsets.UTF_8);
for (var entry : mdnEncodingReplacements.entrySet()) {
encoded = encoded.replaceAll(entry.getKey(), entry.getValue());
}
return encoded;
}
public static String decodeURI(String uri) {
ArrayList<String> allKeys = new ArrayList<>(mdnEncodingReplacements.keySet());
Collections.reverse(allKeys);
for (String strKey : allKeys) {
uri = uri.replaceAll(mdnEncodingReplacements.get(strKey), strKey);
}
return URLDecoder.decode(uri, StandardCharsets.UTF_8);
}
private static void parseRecursive(Object json, Map<String, Object> map, List<String> excludeList, String path, boolean pathInKey) {
if (json instanceof Map.Entry) {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>) json;
@ -663,6 +687,22 @@ public class TbUtils {
}
}
private static boolean isHexadecimal(String value) {
return value != null && (value.contains("0x") || value.contains("0X"));
}
private static String prepareNumberString(String value) {
if (value != null) {
value = value.trim();
if (isHexadecimal(value)) {
value = value.replace("0x", "");
value = value.replace("0X", "");
}
value = value.replace(",", ".");
}
return value;
}
private static boolean isValidRadix(String value, int radix) {
for (int i = 0; i < value.length(); i++) {
if (i == 0 && value.charAt(i) == '-') {

View File

@ -31,13 +31,11 @@ import java.io.IOException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.Random;
@Slf4j
public class TbUtilsTest {
private ExecutionContext ctx;
@ -474,7 +472,16 @@ public class TbUtilsTest {
}
}
@Test
public void encodeDecodeUri_Test() {
String uriOriginal = "-_.!~*'();/?:@&=+$,#ht://example.ж д a/path with spaces/?param1=Київ 1&param2=Україна2";
String uriEncodeExpected = "-_.!~*'();/?:@&=+$,#ht://example.%D0%B6%20%D0%B4%20a/path%20with%20spaces/?param1=%D0%9A%D0%B8%D1%97%D0%B2%201&param2=%D0%A3%D0%BA%D1%80%D0%B0%D1%97%D0%BD%D0%B02";
String uriEncodeActual = TbUtils.encodeURI(uriOriginal);
Assert.assertEquals(uriEncodeExpected, uriEncodeActual);
String uriDecodeActual = TbUtils.decodeURI(uriEncodeActual);
Assert.assertEquals(uriOriginal, uriDecodeActual);
}
private static List<Byte> toList(byte[] data) {
List<Byte> result = new ArrayList<>(data.length);
for (Byte b : data) {