Support function in aggregation #281
This commit is contained in:
@@ -278,6 +278,11 @@
|
|||||||
<groupId>commons-codec</groupId>
|
<groupId>commons-codec</groupId>
|
||||||
<artifactId>commons-codec</artifactId>
|
<artifactId>commons-codec</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-beanutils</groupId>
|
||||||
|
<artifactId>commons-beanutils</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
|
|||||||
184
fizz-core/src/main/java/we/fizz/function/CodecFunc.java
Normal file
184
fizz-core/src/main/java/we/fizz/function/CodecFunc.java
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package we.fizz.function;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.security.Key;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.SecretKeyFactory;
|
||||||
|
import javax.crypto.spec.DESKeySpec;
|
||||||
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import we.util.DigestUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Codec Functions
|
||||||
|
*
|
||||||
|
* @author Francis Dong
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class CodecFunc implements IFunc {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(CodecFunc.class);
|
||||||
|
|
||||||
|
private static final String CHARSET_UTF8 = "UTF-8";
|
||||||
|
|
||||||
|
private static final String IV = "12345678";
|
||||||
|
|
||||||
|
private static CodecFunc singleton;
|
||||||
|
|
||||||
|
public static CodecFunc getInstance() {
|
||||||
|
if (singleton == null) {
|
||||||
|
synchronized (CodecFunc.class) {
|
||||||
|
if (singleton == null) {
|
||||||
|
CodecFunc instance = new CodecFunc();
|
||||||
|
instance.init();
|
||||||
|
singleton = instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CodecFunc() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "codec.md5", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "codec.sha1", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "codec.sha256", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "codec.sha384", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "codec.sha512", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "codec.base64Encode", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "codec.base64Decode", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "codec.aesEncrypt", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "codec.aesDecrypt", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "codec.desEncrypt", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "codec.desDecrypt", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String md5(String data) {
|
||||||
|
return DigestUtils.md5Hex(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String sha1(String data) {
|
||||||
|
return DigestUtils.sha1Hex(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String sha256(String data) {
|
||||||
|
return DigestUtils.sha256Hex(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String sha384(String data) {
|
||||||
|
return DigestUtils.sha384Hex(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String sha512(String data) {
|
||||||
|
return DigestUtils.sha512Hex(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String base64Encode(String data) throws Exception {
|
||||||
|
try {
|
||||||
|
return Base64.getEncoder().encodeToString(data.getBytes(CHARSET_UTF8));
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
LOGGER.error("Base64 encode error, data={}", data, e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String base64Decode(String data) throws Exception {
|
||||||
|
return new String(Base64.getDecoder().decode(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String aesEncrypt(String data, String key) throws Exception {
|
||||||
|
if (StringUtils.isBlank(data) || StringUtils.isBlank(key)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
||||||
|
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(CHARSET_UTF8), "AES");
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
|
||||||
|
byte[] result = cipher.doFinal(data.getBytes(CHARSET_UTF8));
|
||||||
|
return Base64.getEncoder().encodeToString(result);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error("AES encrypt error, data={}", data, e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String aesDecrypt(String data, String key) throws Exception {
|
||||||
|
if (StringUtils.isBlank(data) || StringUtils.isBlank(key)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
||||||
|
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(CHARSET_UTF8), "AES");
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
|
||||||
|
byte[] result = Base64.getDecoder().decode(data);
|
||||||
|
return new String(cipher.doFinal(result));
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error("AES decrypt error, data={}", data, e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String desEncrypt(String data, String key) throws Exception {
|
||||||
|
if (StringUtils.isBlank(data) || StringUtils.isBlank(key)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
DESKeySpec dks = new DESKeySpec(key.getBytes(CHARSET_UTF8));
|
||||||
|
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
|
||||||
|
Key secretKey = keyFactory.generateSecret(dks);
|
||||||
|
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
|
||||||
|
IvParameterSpec iv = new IvParameterSpec(IV.getBytes(CHARSET_UTF8));
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
|
||||||
|
byte[] bytes = cipher.doFinal(data.getBytes(CHARSET_UTF8));
|
||||||
|
return new String(Base64.getEncoder().encode(bytes));
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error("DES eecrypt error, data={}", data, e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String desDecrypt(String data, String key) throws Exception {
|
||||||
|
if (StringUtils.isBlank(data) || StringUtils.isBlank(key)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
DESKeySpec dks = new DESKeySpec(key.getBytes(CHARSET_UTF8));
|
||||||
|
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
|
||||||
|
Key secretKey = keyFactory.generateSecret(dks);
|
||||||
|
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
|
||||||
|
IvParameterSpec iv = new IvParameterSpec(IV.getBytes(CHARSET_UTF8));
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
|
||||||
|
return new String(cipher.doFinal(Base64.getDecoder().decode(data.getBytes(CHARSET_UTF8))), CHARSET_UTF8);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error("DES decrypt error, data={}", data, e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
246
fizz-core/src/main/java/we/fizz/function/DateFunc.java
Normal file
246
fizz-core/src/main/java/we/fizz/function/DateFunc.java
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package we.fizz.function;
|
||||||
|
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import we.fizz.exception.FizzRuntimeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date Functions
|
||||||
|
*
|
||||||
|
* @author Francis Dong
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DateFunc implements IFunc {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(DateFunc.class);
|
||||||
|
|
||||||
|
private static DateFunc singleton;
|
||||||
|
|
||||||
|
public static DateFunc getInstance() {
|
||||||
|
if (singleton == null) {
|
||||||
|
synchronized (DateFunc.class) {
|
||||||
|
if (singleton == null) {
|
||||||
|
DateFunc instance = new DateFunc();
|
||||||
|
instance.init();
|
||||||
|
singleton = instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DateFunc() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "date.timestamp", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "date.now", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "date.add", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "date.formatTs", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "date.changePattern", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date pattern<br>
|
||||||
|
* yyyy-MM-dd
|
||||||
|
*/
|
||||||
|
public final static String DATE_FORMAT = "yyyy-MM-dd";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time pattren<br>
|
||||||
|
* HH:mm:ss
|
||||||
|
*/
|
||||||
|
public final static String TIME_FORMAT = "HH:mm:ss";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Short time pattren<br>
|
||||||
|
* HH:mm
|
||||||
|
*/
|
||||||
|
public final static String SHORT_TIME_FORMAT = "HH:mm";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date time pattern<br>
|
||||||
|
* yyyy-MM-dd HH:mm:ss
|
||||||
|
*/
|
||||||
|
public final static String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns current timestamp (Milliseconds)
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public long timestamp() {
|
||||||
|
return System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns current time with the given pattern<br>
|
||||||
|
* Frequently-used pattern:<br>
|
||||||
|
* yyyy-MM-dd HH:mm:ss<br>
|
||||||
|
* yyyy-MM-dd<br>
|
||||||
|
* HH:mm:ss<br>
|
||||||
|
* HH:mm<br>
|
||||||
|
* yyyy-MM-dd HH:mm:ss Z<br>
|
||||||
|
*
|
||||||
|
* @param pattern [optional] the pattern describing the date and time format,
|
||||||
|
* dafault yyyy-MM-dd HH:mm:ss
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String now(String pattern) {
|
||||||
|
return formatDate(new Date(), pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds or subtracts the specified amount of time to the given calendar field,
|
||||||
|
* based on the calendar's rules. For example, to subtract 5 hours from the
|
||||||
|
* current time of the calendar, you can achieve it by calling:
|
||||||
|
* <p>
|
||||||
|
* <code>add("2021-08-04 14:23:12", "yyyy-MM-dd HH:mm:ss", 4, -5)</code>.
|
||||||
|
*
|
||||||
|
* @param date date string
|
||||||
|
* @param pattern date pattern of the given date string
|
||||||
|
* @param field the calendar field, <br>
|
||||||
|
* 1 for millisecond<br>
|
||||||
|
* 2 for second<br>
|
||||||
|
* 3 for minute<br>
|
||||||
|
* 4 for hour<br>
|
||||||
|
* 5 for date<br>
|
||||||
|
* 6 for month<br>
|
||||||
|
* 7 for year<br>
|
||||||
|
* @param amount the amount of date or time to be added to the field
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String add(String date, String pattern, int field, int amount) {
|
||||||
|
Date d = parse(date, pattern);
|
||||||
|
if (d != null) {
|
||||||
|
// convert to calendar field
|
||||||
|
int calField = 0;
|
||||||
|
switch (field) {
|
||||||
|
case 1:
|
||||||
|
calField = Calendar.MILLISECOND;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
calField = Calendar.SECOND;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
calField = Calendar.MINUTE;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
calField = Calendar.HOUR;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
calField = Calendar.DATE;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
calField = Calendar.MONTH;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
calField = Calendar.YEAR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOGGER.error("invalid field, date={} pattern={} filed={}", date, pattern, field);
|
||||||
|
throw new FizzRuntimeException(
|
||||||
|
"invalid field, date=" + date + "pattern=" + pattern + " filed=" + field);
|
||||||
|
}
|
||||||
|
return formatDate(addToFiled(d, calField, amount), pattern);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format the a timestamp to the given pattern
|
||||||
|
*
|
||||||
|
* @param timestamp
|
||||||
|
* @param pattern
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String formatTs(long timestamp, String pattern) {
|
||||||
|
return formatDate(new Date(timestamp), pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format the a time with source pattern to the target pattern
|
||||||
|
*
|
||||||
|
* @param dateStr date
|
||||||
|
* @param sourcePattern source pattern
|
||||||
|
* @param targetPattern target pattern
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String changePattern(String dateStr, String sourcePattern, String targetPattern) {
|
||||||
|
return formatDate(parse(dateStr, sourcePattern), targetPattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds or subtracts the specified amount of time to the given calendar field
|
||||||
|
*
|
||||||
|
* @param date a Date
|
||||||
|
* @param field field that the times to be add to, such as: Calendar.SECOND,
|
||||||
|
* Calendar.YEAR
|
||||||
|
* @param amount the amount of date or time to be added to the field
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Date addToFiled(Date date, int field, int amount) {
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
cal.setTime(date);
|
||||||
|
cal.add(field, amount);
|
||||||
|
return cal.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse string to Date
|
||||||
|
*
|
||||||
|
* @param dateStr String to be parsed
|
||||||
|
* @param pattern pattern of dateStr
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Date parse(String dateStr, String pattern) {
|
||||||
|
SimpleDateFormat df = new SimpleDateFormat(pattern == null ? DATE_TIME_FORMAT : pattern);
|
||||||
|
try {
|
||||||
|
return df.parse(dateStr);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
LOGGER.error("Parse date error, dateStr={} pattern={}", dateStr, pattern, e);
|
||||||
|
throw new FizzRuntimeException("Parse date error, dateStr=" + dateStr + " pattern=" + pattern, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format date with the given pattern<br>
|
||||||
|
* Frequently-used pattern:<br>
|
||||||
|
* yyyy-MM-dd HH:mm:ss<br>
|
||||||
|
* yyyy-MM-dd<br>
|
||||||
|
* HH:mm:ss<br>
|
||||||
|
* HH:mm<br>
|
||||||
|
* yyyy-MM-dd HH:mm:ss Z<br>
|
||||||
|
*
|
||||||
|
* @param pattern [optional] the pattern describing the date and time format,
|
||||||
|
* dafault yyyy-MM-dd HH:mm:ss
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String formatDate(Date date, String pattern) {
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat(pattern == null ? DATE_TIME_FORMAT : pattern);
|
||||||
|
return sdf.format(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
474
fizz-core/src/main/java/we/fizz/function/FuncExecutor.java
Normal file
474
fizz-core/src/main/java/we/fizz/function/FuncExecutor.java
Normal file
@@ -0,0 +1,474 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package we.fizz.function;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.apache.commons.beanutils.ConvertUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.noear.snack.ONode;
|
||||||
|
import org.reflections.Reflections;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import we.fizz.exception.FizzRuntimeException;
|
||||||
|
import we.fizz.input.Input;
|
||||||
|
import we.fizz.input.PathMapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Register
|
||||||
|
*
|
||||||
|
* @author Francis Dong
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class FuncExecutor {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(FuncExecutor.class);
|
||||||
|
|
||||||
|
private static final Map<String, IFunc> funcMap = new HashMap<>();
|
||||||
|
|
||||||
|
private static Pattern NUMBER_PATTERN = Pattern
|
||||||
|
.compile("^[-\\+]?[\\d]+\\s*[,\\)]{1}|^[-\\+]?[\\d]+\\.[\\d]+\\s*[,\\)]{1}");
|
||||||
|
|
||||||
|
private static FuncExecutor singleton;
|
||||||
|
|
||||||
|
public static FuncExecutor getInstance() {
|
||||||
|
if (singleton == null) {
|
||||||
|
synchronized (FuncExecutor.class) {
|
||||||
|
if (singleton == null) {
|
||||||
|
singleton = new FuncExecutor();
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FuncExecutor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
try {
|
||||||
|
Reflections reflections = new Reflections("we.fizz.function");
|
||||||
|
Set<Class<? extends IFunc>> types = reflections.getSubTypesOf(IFunc.class);
|
||||||
|
for (Class<? extends IFunc> fnType : types) {
|
||||||
|
Method method = fnType.getMethod("getInstance");
|
||||||
|
method.invoke(fnType);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a function instance
|
||||||
|
*
|
||||||
|
* @param namespace a name to identify the given function instance
|
||||||
|
* @param func
|
||||||
|
*/
|
||||||
|
public static void register(String namespace, IFunc funcInstance) {
|
||||||
|
if (StringUtils.isBlank(namespace)) {
|
||||||
|
LOGGER.warn("namespace is required");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!namespace.startsWith(IFunc.NAME_SPACE_PREFIX)) {
|
||||||
|
LOGGER.warn("namespace must start with fn.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (funcInstance == null) {
|
||||||
|
LOGGER.warn("function instance is required");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
funcMap.put(namespace, funcInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute function
|
||||||
|
*
|
||||||
|
* @param funcExpression
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Object exec(ONode ctxNode, String funcExpression) {
|
||||||
|
RecursionContext ctx = new RecursionContext();
|
||||||
|
ctx.setFuncExpression(funcExpression);
|
||||||
|
return doExec(ctxNode, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object doExec(ONode ctxNode, RecursionContext ctx) {
|
||||||
|
String funcExpression = ctx.funcExpression;
|
||||||
|
if (StringUtils.isBlank(funcExpression)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
funcExpression = StringUtils.trim(funcExpression);
|
||||||
|
int pos1 = funcExpression.indexOf("(");
|
||||||
|
if (pos1 == -1) {
|
||||||
|
LOGGER.warn("func expression is invalid, expression: {}", funcExpression);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!funcExpression.endsWith(")")) {
|
||||||
|
LOGGER.warn("func expression is invalid, expression: {}", funcExpression);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String path = funcExpression.substring(0, pos1);
|
||||||
|
int lastDotPos = path.lastIndexOf(".");
|
||||||
|
if (pos1 == -1) {
|
||||||
|
LOGGER.warn("func expression is invalid, expression: {}", funcExpression);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String namespace = path.substring(0, lastDotPos);
|
||||||
|
String methodName = path.substring(lastDotPos + 1);
|
||||||
|
|
||||||
|
Object funcInstance = funcMap.get(path);
|
||||||
|
if (funcInstance == null) {
|
||||||
|
String msg = String.format("function not found: %s, expression: %s", path, funcExpression);
|
||||||
|
LOGGER.warn(msg);
|
||||||
|
throw new FizzRuntimeException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Method method = findMethod(funcInstance.getClass(), methodName);
|
||||||
|
Class[] paramTypes = method.getParameterTypes();
|
||||||
|
ctx.funcExpression = funcExpression;
|
||||||
|
Object[] args = parseArgs(ctxNode, ctx, funcExpression, paramTypes, method.isVarArgs());
|
||||||
|
if (args == null) {
|
||||||
|
return method.invoke(funcInstance);
|
||||||
|
}
|
||||||
|
return method.invoke(funcInstance, args);
|
||||||
|
} catch (FizzRuntimeException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
Throwable targetEx = e.getTargetException();
|
||||||
|
if (targetEx instanceof FizzRuntimeException) {
|
||||||
|
throw (FizzRuntimeException) targetEx;
|
||||||
|
}
|
||||||
|
String msg = targetEx.getMessage();
|
||||||
|
if (msg == null) {
|
||||||
|
msg = String.format("execute function error: %s", funcExpression);
|
||||||
|
}
|
||||||
|
LOGGER.error(msg, targetEx);
|
||||||
|
throw new FizzRuntimeException(msg, targetEx);
|
||||||
|
} catch (Exception e) {
|
||||||
|
String msg = String.format("execute function error: %s", funcExpression);
|
||||||
|
LOGGER.error(msg, e);
|
||||||
|
throw new FizzRuntimeException(msg, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Method findMethod(Class funcClass, String methodName) {
|
||||||
|
Method[] methods = funcClass.getDeclaredMethods();
|
||||||
|
for (Method method : methods) {
|
||||||
|
if (method.getName().equals(methodName)) {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String msg = String.format("method not found: %s, class: %s", methodName, funcClass);
|
||||||
|
LOGGER.warn(msg);
|
||||||
|
throw new FizzRuntimeException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* funcExpression sample:<br>
|
||||||
|
* fn.date.add({step1.request1.response.body.date}, "yyyy-MM-dd HH:mm:ss", 1,
|
||||||
|
* 1000)<br>
|
||||||
|
* fn.date.add(true, fn.date.add({step1.request1.response.body.date},
|
||||||
|
* "yyyy-MM-dd HH:mm:ss", 1, 1000), "yyyy-MM-dd HH:mm:ss\"))}}", 1, 1000)<br>
|
||||||
|
*
|
||||||
|
* @param funcExpression
|
||||||
|
* @param paramTypes
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Object[] parseArgs(ONode ctxNode, RecursionContext ctx, String funcExpression, Class[] paramTypes,
|
||||||
|
boolean isVarArgs) {
|
||||||
|
int pos1 = funcExpression.indexOf("(");
|
||||||
|
// int pos2 = funcExpression.lastIndexOf(")");
|
||||||
|
String argsStr = funcExpression.substring(pos1 + 1);
|
||||||
|
argsStr = StringUtils.trim(argsStr);
|
||||||
|
// check if there is any argument
|
||||||
|
if (StringUtils.isBlank(argsStr)) {
|
||||||
|
if (paramTypes == null || paramTypes.length == 0) {
|
||||||
|
return null;
|
||||||
|
} else if (paramTypes.length == 1 && isVarArgs) {
|
||||||
|
// check if variable arguments
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
throw new FizzRuntimeException(
|
||||||
|
String.format("missing argument, Function Expression: %s", funcExpression));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Object[] args = new Object[paramTypes.length];
|
||||||
|
List<Object> varArgs = new ArrayList<>();
|
||||||
|
for (int i = 0; i < paramTypes.length; i++) {
|
||||||
|
Class clazz = paramTypes[i];
|
||||||
|
if (StringUtils.isBlank(argsStr)) {
|
||||||
|
if (isVarArgs && i == paramTypes.length - 1 && args[i] == null) {
|
||||||
|
args[i] = Array.newInstance(clazz.getComponentType(), 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ArgsStrContainer argsStrContainer = new ArgsStrContainer(argsStr, i);
|
||||||
|
if (argsStr.startsWith("\"")) { // string
|
||||||
|
int pos = findStringEngPos(argsStr);
|
||||||
|
if (pos != -1) {
|
||||||
|
String arg = argsStr.substring(1, pos);
|
||||||
|
if (isVarArgs && i == paramTypes.length - 1) {
|
||||||
|
varArgs.add(arg);
|
||||||
|
args[i] = varArgs.toArray(new String[varArgs.size()]);
|
||||||
|
} else {
|
||||||
|
args[i] = arg;
|
||||||
|
}
|
||||||
|
argsStrContainer = this.trimArgStr(argsStrContainer, pos + 1, isVarArgs, paramTypes.length,
|
||||||
|
funcExpression);
|
||||||
|
argsStr = argsStrContainer.getArgsStr();
|
||||||
|
i = argsStrContainer.getIndex();
|
||||||
|
} else {
|
||||||
|
throw new FizzRuntimeException(
|
||||||
|
String.format("invalid argument: %s, Function Expression: %s", argsStr, funcExpression));
|
||||||
|
}
|
||||||
|
} else if (argsStr.matches("^true\\s*,")) { // boolean
|
||||||
|
if (isVarArgs && i == paramTypes.length - 1) {
|
||||||
|
varArgs.add(true);
|
||||||
|
args[i] = varArgs.toArray(new Boolean[varArgs.size()]);
|
||||||
|
} else {
|
||||||
|
args[i] = true;
|
||||||
|
}
|
||||||
|
argsStrContainer = this.trimArgStr(argsStrContainer, 4, isVarArgs, paramTypes.length, funcExpression);
|
||||||
|
argsStr = argsStrContainer.getArgsStr();
|
||||||
|
i = argsStrContainer.getIndex();
|
||||||
|
} else if (argsStr.matches("^false\\s*,")) { // boolean
|
||||||
|
if (isVarArgs && i == paramTypes.length - 1) {
|
||||||
|
varArgs.add(false);
|
||||||
|
args[i] = varArgs.toArray(new Boolean[varArgs.size()]);
|
||||||
|
} else {
|
||||||
|
args[i] = false;
|
||||||
|
}
|
||||||
|
argsStrContainer = this.trimArgStr(argsStrContainer, 5, isVarArgs, paramTypes.length, funcExpression);
|
||||||
|
argsStr = argsStrContainer.getArgsStr();
|
||||||
|
i = argsStrContainer.getIndex();
|
||||||
|
} else if (argsStr.startsWith("{")) { // reference value
|
||||||
|
int pos = argsStr.indexOf("}", 1);
|
||||||
|
if (pos != -1) {
|
||||||
|
String refKey = argsStr.substring(1, pos);
|
||||||
|
Object arg = PathMapping.getValueByPath(ctxNode, refKey);
|
||||||
|
arg = ConvertUtils.convert(arg, clazz);
|
||||||
|
if (isVarArgs && i == paramTypes.length - 1) {
|
||||||
|
varArgs.add(arg);
|
||||||
|
Object arr = Array.newInstance(clazz.getComponentType(), varArgs.size());
|
||||||
|
for (int j = 0; j < varArgs.size(); j++) {
|
||||||
|
Array.set(arr, j, varArgs.get(j));
|
||||||
|
}
|
||||||
|
args[i] = arr;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
args[i] = arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
argsStrContainer = this.trimArgStr(argsStrContainer, pos + 1, isVarArgs, paramTypes.length,
|
||||||
|
funcExpression);
|
||||||
|
argsStr = argsStrContainer.getArgsStr();
|
||||||
|
i = argsStrContainer.getIndex();
|
||||||
|
} else {
|
||||||
|
throw new FizzRuntimeException(
|
||||||
|
String.format("invalid argument: %s, Function Expression: %s", argsStr, funcExpression));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Matcher m = NUMBER_PATTERN.matcher(argsStr);
|
||||||
|
boolean isNumber = m.find();
|
||||||
|
if (isNumber) {
|
||||||
|
int pos = m.end();
|
||||||
|
String matchedStr = m.group();
|
||||||
|
// Number
|
||||||
|
String strNum = StringUtils.trim(matchedStr.substring(0, pos - 1));
|
||||||
|
if (isVarArgs && i == paramTypes.length - 1) {
|
||||||
|
Object arg = ConvertUtils.convert(strNum, clazz.getComponentType());
|
||||||
|
varArgs.add(arg);
|
||||||
|
Object arr = Array.newInstance(clazz.getComponentType(), varArgs.size());
|
||||||
|
for (int j = 0; j < varArgs.size(); j++) {
|
||||||
|
Array.set(arr, j, varArgs.get(j));
|
||||||
|
}
|
||||||
|
args[i] = arr;
|
||||||
|
} else {
|
||||||
|
Object arg = ConvertUtils.convert(strNum, clazz);
|
||||||
|
args[i] = arg;
|
||||||
|
}
|
||||||
|
argsStrContainer = this.trimArgStr(argsStrContainer, pos - 1, isVarArgs, paramTypes.length,
|
||||||
|
funcExpression);
|
||||||
|
argsStr = argsStrContainer.getArgsStr();
|
||||||
|
i = argsStrContainer.getIndex();
|
||||||
|
} else {
|
||||||
|
// function
|
||||||
|
ctx.funcExpression = argsStr;
|
||||||
|
Object rs = doExec(ctxNode, ctx);
|
||||||
|
if (isVarArgs && i == paramTypes.length - 1) {
|
||||||
|
Object arg = ConvertUtils.convert(rs, clazz.getComponentType());
|
||||||
|
varArgs.add(arg);
|
||||||
|
Object arr = Array.newInstance(clazz.getComponentType(), varArgs.size());
|
||||||
|
for (int j = 0; j < varArgs.size(); j++) {
|
||||||
|
Array.set(arr, j, varArgs.get(j));
|
||||||
|
}
|
||||||
|
args[i] = arr;
|
||||||
|
} else {
|
||||||
|
Object arg = ConvertUtils.convert(rs, clazz);
|
||||||
|
args[i] = arg;
|
||||||
|
}
|
||||||
|
argsStr = ctx.funcExpression;
|
||||||
|
argsStrContainer.setArgsStr(argsStr);
|
||||||
|
argsStrContainer = this.trimArgStr(argsStrContainer, 0, isVarArgs, paramTypes.length,
|
||||||
|
funcExpression);
|
||||||
|
argsStr = argsStrContainer.getArgsStr();
|
||||||
|
i = argsStrContainer.getIndex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.funcExpression = argsStr;
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArgsStrContainer trimArgStr(ArgsStrContainer argsStrContainer, int fromIndex, boolean isVarArgs,
|
||||||
|
int paramTypesLen, String funcExpression) {
|
||||||
|
int i = argsStrContainer.getIndex();
|
||||||
|
String argsStr = argsStrContainer.getArgsStr();
|
||||||
|
if (i == paramTypesLen - 1 || (isVarArgs && i == paramTypesLen - 2)) {
|
||||||
|
boolean hasMore = hasMoreArg(argsStr, fromIndex);
|
||||||
|
if (isVarArgs && hasMore) {
|
||||||
|
argsStr = removeComma(argsStr, fromIndex, funcExpression);
|
||||||
|
if (i == paramTypesLen - 1) {
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (hasCloseParenthesis(argsStr, fromIndex)) {
|
||||||
|
argsStr = removeCloseParenthesis(argsStr, fromIndex, funcExpression);
|
||||||
|
} else {
|
||||||
|
throw new FizzRuntimeException(String.format("invalid argument: %s, Function Expression: %s",
|
||||||
|
argsStr.substring(fromIndex), funcExpression));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
argsStr = removeComma(argsStr, fromIndex, funcExpression);
|
||||||
|
}
|
||||||
|
argsStrContainer.setArgsStr(argsStr);
|
||||||
|
argsStrContainer.setIndex(i);
|
||||||
|
return argsStrContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasMoreArg(String argsStr, int fromIndex) {
|
||||||
|
final int strLen = argsStr.length();
|
||||||
|
if (strLen == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = fromIndex; i < strLen; i++) {
|
||||||
|
if (!Character.isWhitespace(argsStr.charAt(i))) {
|
||||||
|
if (",".equals(String.valueOf(argsStr.charAt(i)))) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasCloseParenthesis(String argsStr, int fromIndex) {
|
||||||
|
final int strLen = argsStr.length();
|
||||||
|
if (strLen == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = fromIndex; i < strLen; i++) {
|
||||||
|
if (!Character.isWhitespace(argsStr.charAt(i))) {
|
||||||
|
if (")".equals(String.valueOf(argsStr.charAt(i)))) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String removeComma(String argsStr, int fromIndex, String funcExpression) {
|
||||||
|
final int strLen = argsStr.length();
|
||||||
|
if (strLen == 0) {
|
||||||
|
return argsStr;
|
||||||
|
}
|
||||||
|
for (int i = fromIndex; i < strLen; i++) {
|
||||||
|
if (!Character.isWhitespace(argsStr.charAt(i))) {
|
||||||
|
if (",".equals(String.valueOf(argsStr.charAt(i)))) {
|
||||||
|
return StringUtils.trim(argsStr.substring(i + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new FizzRuntimeException(String.format("missing comma after argument: %s, Function Expression: %s",
|
||||||
|
argsStr.substring(fromIndex), funcExpression));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String removeCloseParenthesis(String argsStr, int fromIndex, String funcExpression) {
|
||||||
|
final int strLen = argsStr.length();
|
||||||
|
if (strLen == 0 || strLen < fromIndex) {
|
||||||
|
return argsStr;
|
||||||
|
}
|
||||||
|
for (int i = fromIndex; i < strLen; i++) {
|
||||||
|
if (!Character.isWhitespace(argsStr.charAt(i))) {
|
||||||
|
if (")".equals(String.valueOf(argsStr.charAt(i)))) {
|
||||||
|
return StringUtils.trim(argsStr.substring(i + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new FizzRuntimeException(
|
||||||
|
String.format("missing close parenthesis after argument: %s, Function Expression: %s",
|
||||||
|
argsStr.substring(fromIndex), funcExpression));
|
||||||
|
}
|
||||||
|
|
||||||
|
private int findStringEngPos(String ep) {
|
||||||
|
int pos = ep.indexOf("\"", 1);
|
||||||
|
while (pos != -1) {
|
||||||
|
String prevChar = ep.substring(pos - 1, pos);
|
||||||
|
if (!"\\".equals(prevChar)) {
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
pos = ep.indexOf("\"", pos);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
class ArgsStrContainer {
|
||||||
|
private String argsStr;
|
||||||
|
private int index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
class RecursionContext {
|
||||||
|
public String funcExpression;
|
||||||
|
public Object result;
|
||||||
|
}
|
||||||
39
fizz-core/src/main/java/we/fizz/function/IFunc.java
Normal file
39
fizz-core/src/main/java/we/fizz/function/IFunc.java
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package we.fizz.function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function interface
|
||||||
|
*
|
||||||
|
* @author Francis Dong
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface IFunc {
|
||||||
|
|
||||||
|
public final static String NAME_SPACE_PREFIX = "fn.";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init: Register functions to FuncExecutor in the initial stage <br>
|
||||||
|
* <br>
|
||||||
|
* Example: <br>
|
||||||
|
* FuncExecutor.register(NAME_SPACE_PREFIX + "date.timestamp", getInstance());<br>
|
||||||
|
* FuncExecutor.register(NAME_SPACE_PREFIX + "date.now", getInstance());<br>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void init();
|
||||||
|
|
||||||
|
}
|
||||||
124
fizz-core/src/main/java/we/fizz/function/ListFunc.java
Normal file
124
fizz-core/src/main/java/we/fizz/function/ListFunc.java
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package we.fizz.function;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List Functions
|
||||||
|
*
|
||||||
|
* @author Francis Dong
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ListFunc implements IFunc {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(ListFunc.class);
|
||||||
|
|
||||||
|
private static ListFunc singleton;
|
||||||
|
|
||||||
|
public static ListFunc getInstance() {
|
||||||
|
if (singleton == null) {
|
||||||
|
synchronized (ListFunc.class) {
|
||||||
|
if (singleton == null) {
|
||||||
|
ListFunc instance = new ListFunc();
|
||||||
|
instance.init();
|
||||||
|
singleton = instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ListFunc() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "list.expand", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "list.merge", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "list.extract", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expand sublist item to the first level
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<Object> expand(List<List<Object>> data) {
|
||||||
|
List<Object> result = new ArrayList<>();
|
||||||
|
if (data == null || data.size() == 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
for (List<Object> list : data) {
|
||||||
|
result.addAll(list);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge multiple list into one list
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<Object> merge(List<Object>... data) {
|
||||||
|
List<Object> result = new ArrayList<>();
|
||||||
|
if (data == null || data.length == 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
for (List<Object> list : data) {
|
||||||
|
if (list == null || list.size() == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result.addAll(list);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract fields from list
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* @param fields
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<Map<String, Object>> extract(List<Map<String, Object>> data, String... fields) {
|
||||||
|
List<Map<String, Object>> result = new ArrayList<>();
|
||||||
|
if (data == null || data.size() == 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (fields.length == 0) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
for (Map<String, Object> m : data) {
|
||||||
|
Map<String, Object> r = new HashMap<>();
|
||||||
|
for (String field : fields) {
|
||||||
|
r.put(field, m.get(field));
|
||||||
|
}
|
||||||
|
result.add(r);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
162
fizz-core/src/main/java/we/fizz/function/MathFunc.java
Normal file
162
fizz-core/src/main/java/we/fizz/function/MathFunc.java
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package we.fizz.function;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Math Functions
|
||||||
|
*
|
||||||
|
* @author Francis Dong
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MathFunc implements IFunc {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(MathFunc.class);
|
||||||
|
|
||||||
|
private static MathFunc singleton;
|
||||||
|
|
||||||
|
public static MathFunc getInstance() {
|
||||||
|
if (singleton == null) {
|
||||||
|
synchronized (MathFunc.class) {
|
||||||
|
if (singleton == null) {
|
||||||
|
MathFunc instance = new MathFunc();
|
||||||
|
instance.init();
|
||||||
|
singleton = instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MathFunc() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "math.absExact", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "math.negateExact", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "math.addExact", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "math.subtractExact", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "math.multiplyExact", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "math.maxExact", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "math.minExact", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "math.mod", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "math.pow", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "math.sqrt", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "math.random", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "math.absDecimal", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "math.negateDecimal", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "math.addDecimal", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "math.subtractDecimal", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "math.multiplyDecimal", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "math.divideDecimal", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "math.maxDecimal", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "math.minDecimal", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "math.scaleDecimal", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long absExact(long a) {
|
||||||
|
return Math.abs(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long negateExact(long a) {
|
||||||
|
return Math.negateExact(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long addExact(long x, long y) {
|
||||||
|
return Math.addExact(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long subtractExact(long x, long y) {
|
||||||
|
return Math.subtractExact(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long multiplyExact(long x, long y) {
|
||||||
|
return Math.multiplyExact(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long maxExact(long x, long y) {
|
||||||
|
return Math.max(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long minExact(long x, long y) {
|
||||||
|
return Math.min(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long mod(long x, long y) {
|
||||||
|
return Math.floorMod(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double pow(double a, double b) {
|
||||||
|
return Math.pow(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double sqrt(double a) {
|
||||||
|
return Math.sqrt(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a {@code double} value with a positive sign, greater than or equal to
|
||||||
|
* {@code 0.0} and less than {@code 1.0}. Returned values are chosen
|
||||||
|
* pseudorandomly with (approximately) uniform distribution from that range.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public double random() {
|
||||||
|
return Math.random();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double absDecimal(double a) {
|
||||||
|
return BigDecimal.valueOf(a).abs().doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double negateDecimal(double a) {
|
||||||
|
return BigDecimal.valueOf(a).negate().doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double addDecimal(double x, double y) {
|
||||||
|
return BigDecimal.valueOf(x).add(BigDecimal.valueOf(y)).doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double subtractDecimal(double x, double y) {
|
||||||
|
return BigDecimal.valueOf(x).subtract(BigDecimal.valueOf(y)).doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double multiplyDecimal(double x, double y) {
|
||||||
|
return BigDecimal.valueOf(x).multiply(BigDecimal.valueOf(y)).doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double divideDecimal(double x, double y) {
|
||||||
|
return BigDecimal.valueOf(x).divide(BigDecimal.valueOf(y)).doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double maxDecimal(double x, double y) {
|
||||||
|
return BigDecimal.valueOf(x).max(BigDecimal.valueOf(y)).doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double minDecimal(double x, double y) {
|
||||||
|
return BigDecimal.valueOf(x).min(BigDecimal.valueOf(y)).doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double scaleDecimal(double a, int scale) {
|
||||||
|
return BigDecimal.valueOf(a).setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
148
fizz-core/src/main/java/we/fizz/function/StringFunc.java
Normal file
148
fizz-core/src/main/java/we/fizz/function/StringFunc.java
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package we.fizz.function;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import we.fizz.exception.FizzRuntimeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String Functions
|
||||||
|
*
|
||||||
|
* @author Francis Dong
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class StringFunc implements IFunc {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(StringFunc.class);
|
||||||
|
|
||||||
|
private static StringFunc singleton;
|
||||||
|
|
||||||
|
public static StringFunc getInstance() {
|
||||||
|
if (singleton == null) {
|
||||||
|
synchronized (StringFunc.class) {
|
||||||
|
if (singleton == null) {
|
||||||
|
StringFunc instance = new StringFunc();
|
||||||
|
instance.init();
|
||||||
|
singleton = instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
private StringFunc() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "string.concat", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "string.concatws", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "string.substring", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "string.indexOf", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "string.startsWith", this);
|
||||||
|
FuncExecutor.register(NAME_SPACE_PREFIX + "string.endsWith", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concat strings
|
||||||
|
*
|
||||||
|
* @param strs
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String concat(String... strs) {
|
||||||
|
return StringUtils.join(strs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concat with separator
|
||||||
|
*
|
||||||
|
* @param strs
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String concatws(String separator, String... strs) {
|
||||||
|
return StringUtils.join(strs, separator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string that is a substring of this string. The substring begins at
|
||||||
|
* the specified {@code beginIndex} and extends to the character at index
|
||||||
|
* {@code endIndex - 1}. Thus the length of the substring is
|
||||||
|
* {@code endIndex-beginIndex}.
|
||||||
|
*
|
||||||
|
* @param str
|
||||||
|
* @param beginIndex
|
||||||
|
* @param endIndex
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String substring(String str, int beginIndex, int... endIndex) {
|
||||||
|
if (StringUtils.isBlank(str)) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
if (endIndex != null && endIndex.length > 0) {
|
||||||
|
if (endIndex.length > 1) {
|
||||||
|
LOGGER.error("invalid argument: endIndex");
|
||||||
|
throw new FizzRuntimeException("invalid argument: endIndex");
|
||||||
|
}
|
||||||
|
return str.substring(beginIndex, endIndex[0]);
|
||||||
|
}
|
||||||
|
return str.substring(beginIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index within this string of the first occurrence of the specified
|
||||||
|
* substring.
|
||||||
|
*
|
||||||
|
* @param str
|
||||||
|
* @param substr
|
||||||
|
* @return the index of the first occurrence of the specified substring, or
|
||||||
|
* {@code -1} if there is no such occurrence.
|
||||||
|
*/
|
||||||
|
public int indexOf(String str, String substr) {
|
||||||
|
return str.indexOf(substr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if this string starts with the specified prefix.
|
||||||
|
*
|
||||||
|
* @param prefix the prefix.
|
||||||
|
* @return {@code true} if the character sequence represented by the argument is
|
||||||
|
* a prefix of the character sequence represented by this string;
|
||||||
|
* {@code false} otherwise. Note also that {@code true} will be returned
|
||||||
|
* if the argument is an empty string or is equal to this {@code String}
|
||||||
|
* object as determined by the {@link #equals(Object)} method.
|
||||||
|
*/
|
||||||
|
public boolean startsWith(String str, String prefix) {
|
||||||
|
return str.startsWith(prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if this string starts with the specified prefix.
|
||||||
|
*
|
||||||
|
* @param prefix the prefix.
|
||||||
|
* @return {@code true} if the character sequence represented by the argument is
|
||||||
|
* a prefix of the character sequence represented by this string;
|
||||||
|
* {@code false} otherwise. Note also that {@code true} will be returned
|
||||||
|
* if the argument is an empty string or is equal to this {@code String}
|
||||||
|
* object as determined by the {@link #equals(Object)} method.
|
||||||
|
*/
|
||||||
|
public boolean endsWith(String str, String suffix) {
|
||||||
|
return str.endsWith(suffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -27,6 +27,8 @@ import org.noear.snack.ONode;
|
|||||||
import we.constants.CommonConstants;
|
import we.constants.CommonConstants;
|
||||||
import we.fizz.StepContext;
|
import we.fizz.StepContext;
|
||||||
import we.fizz.exception.FizzRuntimeException;
|
import we.fizz.exception.FizzRuntimeException;
|
||||||
|
import we.fizz.function.FuncExecutor;
|
||||||
|
import we.fizz.function.IFunc;
|
||||||
import we.util.MapUtil;
|
import we.util.MapUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -194,6 +196,13 @@ public class PathMapping {
|
|||||||
|
|
||||||
private static Object getRefValue(ONode ctxNode, String type, String path) {
|
private static Object getRefValue(ONode ctxNode, String type, String path) {
|
||||||
Object obj = null;
|
Object obj = null;
|
||||||
|
// check if it is a function
|
||||||
|
if (path.startsWith(IFunc.NAME_SPACE_PREFIX)) {
|
||||||
|
obj = FuncExecutor.getInstance().exec(ctxNode, path);
|
||||||
|
if (obj != null && type != null) {
|
||||||
|
obj = cast(obj, type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
try {
|
try {
|
||||||
String p = path;
|
String p = path;
|
||||||
String defaultValue = null;
|
String defaultValue = null;
|
||||||
@@ -214,6 +223,7 @@ public class PathMapping {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
throw new FizzRuntimeException(String.format("path mapping errer: %s , path mapping data: %s %s", e.getMessage(), type, path), e);
|
throw new FizzRuntimeException(String.format("path mapping errer: %s , path mapping data: %s %s", e.getMessage(), type, path), e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,6 +269,8 @@ public class PathMapping {
|
|||||||
case "string": {
|
case "string": {
|
||||||
if (obj instanceof ONode) {
|
if (obj instanceof ONode) {
|
||||||
obj = ((ONode) obj).val().getString();
|
obj = ((ONode) obj).val().getString();
|
||||||
|
} else {
|
||||||
|
obj = String.valueOf(obj.toString());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
125
fizz-core/src/test/java/we/fizz/function/CodecFuncTests.java
Normal file
125
fizz-core/src/test/java/we/fizz/function/CodecFuncTests.java
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package we.fizz.function;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.noear.snack.ONode;
|
||||||
|
|
||||||
|
import we.fizz.input.PathMapping;
|
||||||
|
import we.util.DigestUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Francis Dong
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class CodecFuncTests {
|
||||||
|
@Test
|
||||||
|
void contextLoads() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMd5() {
|
||||||
|
String funcExpression = "fn.codec.md5(\"abc\")";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("900150983cd24fb0d6963f7d28e17f72", result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMd5_2() {
|
||||||
|
String funcExpression = "fn.codec.md5(fn.date.add(fn.date.add(\"2021-07-09 22:44:55\", \"yyyy-MM-dd HH:mm:ss\", 1, fn.math.addExact(999,1)), \"yyyy-MM-dd HH:mm:ss\", fn.math.addExact(0,1), 1000))";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals(DigestUtils.md5Hex("2021-07-09 22:44:57"), result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSha1() {
|
||||||
|
String funcExpression = "fn.codec.sha1(\"abc\")";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("a9993e364706816aba3e25717850c26c9cd0d89d", result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSha256() {
|
||||||
|
String funcExpression = "fn.codec.sha256(\"abc\")";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSha384() {
|
||||||
|
String funcExpression = "fn.codec.sha384(\"abc\")";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSha512() {
|
||||||
|
String funcExpression = "fn.codec.sha512(\"abc\")";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testBase64Encode() {
|
||||||
|
String funcExpression = "fn.codec.base64Encode(\"Base64编码介绍\")";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("QmFzZTY057yW56CB5LuL57uN", result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testBase64Decode() {
|
||||||
|
String funcExpression = "fn.codec.base64Decode(\"QmFzZTY057yW56CB5LuL57uN\")";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("Base64编码介绍", result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testAesEncrypt() {
|
||||||
|
String funcExpression = "fn.codec.aesEncrypt(\"abc\", \"12345678123456781234567812345678\")";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("MQn0lgH5W6tS6Ii2c7UeSg==", result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testAesDecrypt() {
|
||||||
|
String funcExpression = "fn.codec.aesDecrypt(\"MQn0lgH5W6tS6Ii2c7UeSg==\", \"12345678123456781234567812345678\")";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("abc", result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDesEncrypt() {
|
||||||
|
String funcExpression = "fn.codec.desEncrypt(\"abc\", \"12345678123456781234567812345678\")";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("9YR6ZPdZufM=", result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDesDecrypt() {
|
||||||
|
String funcExpression = "fn.codec.desDecrypt(\"9YR6ZPdZufM=\", \"12345678123456781234567812345678\")";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("abc", result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
69
fizz-core/src/test/java/we/fizz/function/DateFuncTests.java
Normal file
69
fizz-core/src/test/java/we/fizz/function/DateFuncTests.java
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package we.fizz.function;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Francis Dong
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class DateFuncTests {
|
||||||
|
@Test
|
||||||
|
void contextLoads() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testExec() {
|
||||||
|
String funcExpression = "fn.date.timestamp()";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
System.out.println(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testAdd() {
|
||||||
|
String funcExpression = "fn.date.add(\"2021-07-09 22:44:55\", \"yyyy-MM-dd HH:mm:ss\", 1, 1000)";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("2021-07-09 22:44:56", result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testEmbeddedAdd() {
|
||||||
|
String funcExpression = "fn.date.add(fn.date.add(\"2021-07-09 22:44:55\", \"yyyy-MM-dd HH:mm:ss\", 1, 1000), \"yyyy-MM-dd HH:mm:ss\", 1, 1000)";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("2021-07-09 22:44:57", result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFormatTs() {
|
||||||
|
String funcExpression = "fn.date.formatTs(1628825352227, \"yyyy-MM-dd HH:mm:ss\")";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("2021-08-13 11:29:12", result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testChangePattern() {
|
||||||
|
String funcExpression = "fn.date.changePattern(\"2021-07-09 22:44:55\", \"yyyy-MM-dd HH:mm:ss\", \"MM-dd HH:mm\")";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("07-09 22:44", result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
133
fizz-core/src/test/java/we/fizz/function/ListFuncTests.java
Normal file
133
fizz-core/src/test/java/we/fizz/function/ListFuncTests.java
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package we.fizz.function;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.noear.snack.ONode;
|
||||||
|
|
||||||
|
import we.fizz.input.PathMapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Francis Dong
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
|
class ListFuncTests {
|
||||||
|
@Test
|
||||||
|
void contextLoads() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> createRecord(String key, Object value) {
|
||||||
|
Map<String, Object> m = new HashMap<>();
|
||||||
|
m.put(key, value);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> createRecord2(int index) {
|
||||||
|
Map<String, Object> m = new HashMap<>();
|
||||||
|
m.put("a", "a" + index);
|
||||||
|
m.put("b", "b" + index);
|
||||||
|
m.put("c", "c" + index);
|
||||||
|
m.put("d", "d" + index);
|
||||||
|
m.put("e", "e" + index);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testExpand() {
|
||||||
|
List<List<Object>> data = new ArrayList<>();
|
||||||
|
|
||||||
|
List<Object> subList1 = new ArrayList<>();
|
||||||
|
subList1.add(createRecord("a", "a1"));
|
||||||
|
subList1.add(createRecord("a", "a2"));
|
||||||
|
subList1.add(createRecord("a", "a3"));
|
||||||
|
|
||||||
|
List<Object> subList2 = new ArrayList<>();
|
||||||
|
subList2.add(createRecord("a", "a4"));
|
||||||
|
subList2.add(createRecord("a", "a5"));
|
||||||
|
subList2.add(createRecord("a", "a6"));
|
||||||
|
|
||||||
|
data.add(subList1);
|
||||||
|
data.add(subList2);
|
||||||
|
|
||||||
|
ONode ctxNode = ONode.load(new HashMap());
|
||||||
|
PathMapping.setByPath(ctxNode, "test.data", data, true);
|
||||||
|
|
||||||
|
String funcExpression = "fn.list.expand({test.data})";
|
||||||
|
List<Object> result = (List<Object>) FuncExecutor.getInstance().exec(ctxNode, funcExpression);
|
||||||
|
assertEquals(6, result.size());
|
||||||
|
assertEquals("a2", ((Map<String, Object>) result.get(1)).get("a").toString());
|
||||||
|
assertEquals("a4", ((Map<String, Object>) result.get(3)).get("a").toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMerge() {
|
||||||
|
List<Object> subList1 = new ArrayList<>();
|
||||||
|
subList1.add(createRecord("a", "a1"));
|
||||||
|
subList1.add(createRecord("a", "a2"));
|
||||||
|
subList1.add(createRecord("a", "a3"));
|
||||||
|
|
||||||
|
List<Object> subList2 = new ArrayList<>();
|
||||||
|
subList2.add(createRecord("a", "a4"));
|
||||||
|
subList2.add(createRecord("a", "a5"));
|
||||||
|
subList2.add(createRecord("a", "a6"));
|
||||||
|
|
||||||
|
|
||||||
|
ONode ctxNode = ONode.load(new HashMap());
|
||||||
|
PathMapping.setByPath(ctxNode, "test.data1", subList1, true);
|
||||||
|
PathMapping.setByPath(ctxNode, "test.data2", subList2, true);
|
||||||
|
|
||||||
|
String funcExpression = "fn.list.merge({test.data1}, {test.data2})";
|
||||||
|
List<Object> result = (List<Object>) FuncExecutor.getInstance().exec(ctxNode, funcExpression);
|
||||||
|
assertEquals(6, result.size());
|
||||||
|
assertEquals("a2", ((Map<String, Object>) result.get(1)).get("a").toString());
|
||||||
|
assertEquals("a4", ((Map<String, Object>) result.get(3)).get("a").toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testExtract() {
|
||||||
|
List<Object> subList1 = new ArrayList<>();
|
||||||
|
subList1.add(createRecord2(1));
|
||||||
|
subList1.add(createRecord2(2));
|
||||||
|
subList1.add(createRecord2(3));
|
||||||
|
subList1.add(createRecord2(4));
|
||||||
|
subList1.add(createRecord2(5));
|
||||||
|
|
||||||
|
|
||||||
|
ONode ctxNode = ONode.load(new HashMap());
|
||||||
|
PathMapping.setByPath(ctxNode, "test.data", subList1, true);
|
||||||
|
|
||||||
|
String funcExpression = "fn.list.extract({test.data}, \"c\",\"b\", \"e\")";
|
||||||
|
List<Object> result = (List<Object>) FuncExecutor.getInstance().exec(ctxNode, funcExpression);
|
||||||
|
assertEquals(5, result.size());
|
||||||
|
assertEquals("c2", ((Map<String, Object>) result.get(1)).get("c").toString());
|
||||||
|
assertEquals("e4", ((Map<String, Object>) result.get(3)).get("e").toString());
|
||||||
|
assertEquals(null, ((Map<String, Object>) result.get(3)).get("a"));
|
||||||
|
assertEquals(null, ((Map<String, Object>) result.get(3)).get("d"));
|
||||||
|
// System.out.println(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
179
fizz-core/src/test/java/we/fizz/function/MathFuncTests.java
Normal file
179
fizz-core/src/test/java/we/fizz/function/MathFuncTests.java
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package we.fizz.function;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.noear.snack.ONode;
|
||||||
|
|
||||||
|
import we.fizz.input.PathMapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Francis Dong
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class MathFuncTests {
|
||||||
|
@Test
|
||||||
|
void contextLoads() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testAbsExact() {
|
||||||
|
String funcExpression = "fn.math.absExact(-3)";
|
||||||
|
long result = (long) FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals(3, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testNegateExact() {
|
||||||
|
String funcExpression = "fn.math.negateExact(4)";
|
||||||
|
long result = (long) FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals(-4, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testNegateExact2() {
|
||||||
|
String funcExpression = "fn.math.negateExact(-4)";
|
||||||
|
long result = (long) FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals(4, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testAddExact() {
|
||||||
|
String funcExpression = "fn.math.addExact(14,-1)";
|
||||||
|
long result = (long) FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals(13, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSubtractExact() {
|
||||||
|
String funcExpression = "fn.math.subtractExact(14,-1)";
|
||||||
|
long result = (long) FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals(15, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMultiplyExact() {
|
||||||
|
String funcExpression = "fn.math.multiplyExact(14,2)";
|
||||||
|
long result = (long) FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals(28, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMaxExact() {
|
||||||
|
String funcExpression = "fn.math.maxExact(14,2)";
|
||||||
|
long result = (long) FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals(14, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMinExact() {
|
||||||
|
String funcExpression = "fn.math.minExact(14,2)";
|
||||||
|
long result = (long) FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals(2, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMod() {
|
||||||
|
String funcExpression = "fn.math.mod(13,2)";
|
||||||
|
long result = (long) FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals(1, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testPow() {
|
||||||
|
String funcExpression = "fn.math.pow(2,3)";
|
||||||
|
double result = (double) FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals(8, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSqrt() {
|
||||||
|
String funcExpression = "fn.math.sqrt(4)";
|
||||||
|
double result = (double) FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals(2, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testAbsDecimal() {
|
||||||
|
String funcExpression = "fn.math.absDecimal(-4)";
|
||||||
|
double result = (double) FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals(4, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testNegateDecimal() {
|
||||||
|
String funcExpression = "fn.math.negateDecimal(4)";
|
||||||
|
double result = (double) FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals(-4, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSubtractDecimal() {
|
||||||
|
String funcExpression = "fn.math.subtractDecimal(4,1.3)";
|
||||||
|
double result = (double) FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals(2.7, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMultiplyDecimal() {
|
||||||
|
String funcExpression = "fn.math.multiplyDecimal(4,2.2)";
|
||||||
|
double result = (double) FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals(8.8, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDivideDecimal() {
|
||||||
|
String funcExpression = "fn.math.divideDecimal(4.8,2)";
|
||||||
|
double result = (double) FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals(2.4, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMaxDecimal() {
|
||||||
|
String funcExpression = "fn.math.maxDecimal(4.8,2)";
|
||||||
|
double result = (double) FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals(4.8, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMinDecimal() {
|
||||||
|
String funcExpression = "fn.math.minDecimal(4.8,2)";
|
||||||
|
double result = (double) FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals(2, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testScaleDecimal() {
|
||||||
|
String funcExpression = "fn.math.scaleDecimal(4.8456,2)";
|
||||||
|
double result = (double) FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals(4.85, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testRandom() {
|
||||||
|
String funcExpression = "fn.math.random()";
|
||||||
|
double result = (double) FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
// System.out.println(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
110
fizz-core/src/test/java/we/fizz/function/StringFuncTests.java
Normal file
110
fizz-core/src/test/java/we/fizz/function/StringFuncTests.java
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package we.fizz.function;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.noear.snack.ONode;
|
||||||
|
|
||||||
|
import we.fizz.input.PathMapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Francis Dong
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class StringFuncTests {
|
||||||
|
@Test
|
||||||
|
void contextLoads() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConcat() {
|
||||||
|
String funcExpression = "fn.string.concat(\"2021-07-09 22:44:55\")";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("2021-07-09 22:44:55", result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConcat2() {
|
||||||
|
String funcExpression = "fn.string.concat(\"2021-07-09 22:44:55\", \"yyyy-MM-dd HH:mm:ss\")";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("2021-07-09 22:44:55yyyy-MM-dd HH:mm:ss", result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConcatws() {
|
||||||
|
String funcExpression = "fn.string.concatws(\",\" , \"2021-07-09 22:44:55\", \"yyyy-MM-dd HH:mm:ss\")";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("2021-07-09 22:44:55,yyyy-MM-dd HH:mm:ss", result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSubstring() {
|
||||||
|
String funcExpression = "fn.string.substring(\"2021-07-09 22:44:55\", 1 , 4)";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("2021-07-09 22:44:55".substring(1, 4), result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSubstring2() {
|
||||||
|
ONode ctxNode = ONode.load(new HashMap());
|
||||||
|
|
||||||
|
Map<String, Object> m = new HashMap<>();
|
||||||
|
m.put("a", "1");
|
||||||
|
m.put("b", "1");
|
||||||
|
|
||||||
|
PathMapping.setByPath(ctxNode, "data.dateStr", "2021-07-09 22:44:55", true);
|
||||||
|
PathMapping.setByPath(ctxNode, "data.startIndex", 1, true);
|
||||||
|
PathMapping.setByPath(ctxNode, "data", m, false);
|
||||||
|
|
||||||
|
String funcExpression = "fn.string.substring({data.dateStr}, {data.startIndex})";
|
||||||
|
// String funcExpression = "fn.string.substring(\"2021-07-09 22:44:55\", 1)";
|
||||||
|
Object result = FuncExecutor.getInstance().exec(ctxNode, funcExpression);
|
||||||
|
assertEquals("2021-07-09 22:44:55".substring(1), result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testIndexOf() {
|
||||||
|
String funcExpression = "fn.string.indexOf(\"2021-07-09 22:44:55\", \"07\")";
|
||||||
|
int result = (int)FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("2021-07-09 22:44:55".indexOf("07"), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testStartsWith() {
|
||||||
|
String funcExpression = "fn.string.startsWith(\"2021-07-09 22:44:55\", \"2021\")";
|
||||||
|
boolean result = (boolean)FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("2021-07-09 22:44:55".startsWith("2021"), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testEndsWith() {
|
||||||
|
String funcExpression = "fn.string.endsWith(\"2021-07-09 22:44:55\", \"44:55\")";
|
||||||
|
boolean result = (boolean)FuncExecutor.getInstance().exec(null, funcExpression);
|
||||||
|
assertEquals("2021-07-09 22:44:55".endsWith("44:55"), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
6
pom.xml
6
pom.xml
@@ -370,6 +370,12 @@
|
|||||||
<artifactId>commons-codec</artifactId>
|
<artifactId>commons-codec</artifactId>
|
||||||
<version>1.15</version>
|
<version>1.15</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-beanutils</groupId>
|
||||||
|
<artifactId>commons-beanutils</artifactId>
|
||||||
|
<version>1.9.4</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user