diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java index 0708d1c959..d275466b95 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java @@ -64,6 +64,10 @@ public class TbUtils { String.class))); parserConfig.addImport("parseInt", new MethodStub(TbUtils.class.getMethod("parseInt", String.class, int.class))); + parserConfig.addImport("parseLong", new MethodStub(TbUtils.class.getMethod("parseLong", + String.class))); + parserConfig.addImport("parseLong", new MethodStub(TbUtils.class.getMethod("parseLong", + String.class, int.class))); parserConfig.addImport("parseFloat", new MethodStub(TbUtils.class.getMethod("parseFloat", String.class))); parserConfig.addImport("parseDouble", new MethodStub(TbUtils.class.getMethod("parseDouble", @@ -76,6 +80,10 @@ public class TbUtils { String.class))); parserConfig.addImport("parseHexToInt", new MethodStub(TbUtils.class.getMethod("parseHexToInt", String.class, boolean.class))); + parserConfig.addImport("parseHexToLong", new MethodStub(TbUtils.class.getMethod("parseHexToLong", + String.class))); + parserConfig.addImport("parseHexToLong", new MethodStub(TbUtils.class.getMethod("parseHexToLong", + String.class, boolean.class))); parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt", List.class, int.class, int.class))); parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt", @@ -84,6 +92,14 @@ public class TbUtils { byte[].class, int.class, int.class))); parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt", byte[].class, int.class, int.class, boolean.class))); + parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong", + List.class, int.class, int.class))); + parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong", + List.class, int.class, int.class, boolean.class))); + parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong", + byte[].class, int.class, int.class))); + parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong", + byte[].class, int.class, int.class, boolean.class))); parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", byte[].class, int.class, boolean.class))); parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", @@ -92,16 +108,18 @@ public class TbUtils { List.class, int.class, boolean.class))); parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", List.class, int.class))); - parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", - byte[].class, int.class, boolean.class))); parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", byte[].class, int.class))); parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", - List.class, int.class, boolean.class))); + byte[].class, int.class, boolean.class))); + parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", + List.class, int.class))); parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", - List.class, int.class))); + List.class, int.class, boolean.class))); parserConfig.addImport("toFixed", new MethodStub(TbUtils.class.getMethod("toFixed", double.class, int.class))); + parserConfig.addImport("toFixed", new MethodStub(TbUtils.class.getMethod("toFixed", + float.class, int.class))); parserConfig.addImport("hexToBytes", new MethodStub(TbUtils.class.getMethod("hexToBytes", ExecutionContext.class, String.class))); parserConfig.addImport("base64ToHex", new MethodStub(TbUtils.class.getMethod("base64ToHex", @@ -204,6 +222,38 @@ public class TbUtils { return null; } + public static Long parseLong(String value) { + if (value != null) { + try { + int radix = 10; + if (isHexadecimal(value)) { + radix = 16; + } + return Long.parseLong(prepareNumberString(value), radix); + } catch (NumberFormatException e) { + Double d = parseDouble(value); + if (d != null) { + return d.longValue(); + } + } + } + return null; + } + + public static Long parseLong(String value, int radix) { + if (value != null) { + try { + return Long.parseLong(prepareNumberString(value), radix); + } catch (NumberFormatException e) { + Double d = parseDouble(value); + if (d != null) { + return d.longValue(); + } + } + } + return null; + } + public static Float parseFloat(String value) { if (value != null) { try { @@ -251,6 +301,33 @@ public class TbUtils { return parseBytesToInt(data, 0, data.length, bigEndian); } + public static long parseLittleEndianHexToLong(String hex) { + return parseHexToLong(hex, false); + } + + public static long parseBigEndianHexToLong(String hex) { + return parseHexToInt(hex, true); + } + + public static long parseHexToLong(String hex) { + return parseHexToInt(hex, true); + } + + public static long parseHexToLong(String hex, boolean bigEndian) { + int length = hex.length(); + if (length > 16) { + throw new IllegalArgumentException("Hex string is too large. Maximum 8 symbols allowed."); + } + if (length % 2 > 0) { + throw new IllegalArgumentException("Hex string must be even-length."); + } + byte[] data = new byte[length / 2]; + for (int i = 0; i < length; i += 2) { + data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16)); + } + return parseBytesToLong(data, 0, data.length, bigEndian); + } + public static ExecutionArrayList hexToBytes(ExecutionContext ctx, String hex) { int len = hex.length(); if (len % 2 > 0) { @@ -312,66 +389,93 @@ public class TbUtils { return bb.getInt(); } - public static float parseBytesToFloat(byte[] data, int offset) { - return parseBytesToFloat(data, offset, true); + public static long parseBytesToLong(List data, int offset, int length) { + return parseBytesToLong(data, offset, length, true); } - public static float parseBytesToFloat(byte[] data, int offset, boolean bigEndian) { - if (data != null && data.length > 0) { - int length = 4; - if (offset > data.length) { - throw new IllegalArgumentException("Offset: " + offset + " is out of bounds for array with length: " + data.length + "!"); - } - if ((offset + length) > data.length) { - throw new IllegalArgumentException("Default length is always 4 bytes. Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!"); - } - int i = parseBytesToInt(data, offset, length, bigEndian); - return Float.intBitsToFloat(i); - } else { - throw new IllegalArgumentException("Array is null or array length is 0!"); + public static long parseBytesToLong(List data, int offset, int length, boolean bigEndian) { + final byte[] bytes = new byte[data.size()]; + for (int i = 0; i < bytes.length; i++) { + bytes[i] = data.get(i); } + return parseBytesToLong(bytes, offset, length, bigEndian); } - public static float parseBytesToFloat(List data, int offset) { + + public static long parseBytesToLong(byte[] data, int offset, int length) { + return parseBytesToLong(data, offset, length, true); + } + + public static long parseBytesToLong(byte[] data, int offset, int length, boolean bigEndian) { + if (offset > data.length) { + throw new IllegalArgumentException("Offset: " + offset + " is out of bounds for array with length: " + data.length + "!"); + } + if (length > 8) { + throw new IllegalArgumentException("Length: " + length + " is too large. Maximum 4 bytes is allowed!"); + } + if (offset + length > data.length) { + throw new IllegalArgumentException("Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!"); + } + var bb = ByteBuffer.allocate(8); + if (!bigEndian) { + bb.order(ByteOrder.LITTLE_ENDIAN); + } + bb.position(bigEndian ? 8 - length : 0); + bb.put(data, offset, length); + bb.position(0); + return bb.getLong(); + } + + public static float parseBytesToFloat(byte[] data, int offset) { return parseBytesToFloat(data, offset, true); } + public static float parseBytesToFloat(List data, int offset) { + return parseBytesToFloat(data, offset,true); + } + public static float parseBytesToFloat(List data, int offset, boolean bigEndian) { return parseBytesToFloat(Bytes.toArray(data), offset, bigEndian); } - - public static double parseBytesToDouble(byte[] data, int offset) { - return parseBytesToDouble(data, offset, true); + public static float parseBytesToFloat(byte[] data, int offset, boolean bigEndian) { + byte[] bytesToNumber = prepareBytesToNumber (data, offset, 4, bigEndian); + return ByteBuffer.wrap(bytesToNumber).getFloat(); } - public static double parseBytesToDouble(byte[] data, int offset, boolean bigEndian) { - if (data != null && data.length > 0) { - int length = 8; - if (offset > data.length) { - throw new IllegalArgumentException("Offset: " + offset + " is out of bounds for array with length: " + data.length + "!"); - } - if ((offset + length) > data.length) { - throw new IllegalArgumentException("Default length is always 4 bytes. Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!"); - } - byte[] dataBytesArray = Arrays.copyOfRange(data, offset, (offset+length)); - if (!bigEndian) { - ArrayUtils.reverse(dataBytesArray); - } - return ByteBuffer.wrap(dataBytesArray).getDouble(); - } else { - throw new IllegalArgumentException("Array is null or array length is 0!"); - } + public static double parseBytesToDouble(byte[] data, int offset) { + return parseBytesToDouble(data, offset, true); } public static double parseBytesToDouble(List data, int offset) { - return parseBytesToDouble(data, offset, true); + return parseBytesToDouble(data, offset,true); } public static double parseBytesToDouble(List data, int offset, boolean bigEndian) { return parseBytesToDouble(Bytes.toArray(data), offset, bigEndian); } + public static double parseBytesToDouble(byte[] data, int offset, boolean bigEndian) { + byte[] bytesToNumber = prepareBytesToNumber (data, offset, 8, bigEndian); + return ByteBuffer.wrap(bytesToNumber).getDouble(); + } + + private static byte [] prepareBytesToNumber(byte[] data, int offset, int length, boolean bigEndian) { + if (offset > data.length) { + throw new IllegalArgumentException("Offset: " + offset + " is out of bounds for array with length: " + data.length + "!"); + } + if ((offset + length) > data.length) { + throw new IllegalArgumentException("Default length is always " + length + " bytes. Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!"); + } + byte[] bytesToNumber = new byte[length]; + byte[] dataBytesArray = Arrays.copyOfRange(data, offset, (offset+length)); + if (!bigEndian) { + ArrayUtils.reverse(dataBytesArray); + } + System.arraycopy(dataBytesArray, 0, bytesToNumber, 0, length); + return bytesToNumber; + } + public static String bytesToHex(ExecutionArrayList bytesList) { byte[] bytes = new byte[bytesList.size()]; for (int i = 0; i < bytesList.size(); i++) { @@ -394,6 +498,10 @@ public class TbUtils { return BigDecimal.valueOf(value).setScale(precision, RoundingMode.HALF_UP).doubleValue(); } + public static float toFixed(float value, int precision) { + 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")); }