Skip to content

Commit

Permalink
feat: aviator fn for str contains, exists & matches (#1106)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikezzb authored Jul 19, 2023
1 parent e144c50 commit aaaccf0
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ void deleteAlertDefine() {
@Test
void getAlertDefine() {
long id = 1L;
AlertDefine alertDefine = AlertDefine.builder().id(1L).build();
AlertDefine alertDefine = AlertDefine.builder().id(id).build();
when(alertDefineDao.findById(id)).thenReturn(Optional.of(alertDefine));
assertDoesNotThrow(() -> alertDefineService.getAlertDefine(id));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@
import com.googlecode.aviator.runtime.function.AbstractFunction;
import com.googlecode.aviator.runtime.type.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Map;
import java.util.regex.Pattern;

/**
*
Expand All @@ -43,6 +45,8 @@ public void configAviatorEvaluator() {
AviatorEvaluator.getInstance()
.useLRUExpressionCache(AVIATOR_LRU_CACHE_SIZE)
.addFunction(new StrEqualFunction());

// 配置自定义aviator函数
AviatorEvaluator.getInstance().addOpFunction(OperatorType.BIT_OR, new AbstractFunction() {
@Override
public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
Expand All @@ -66,6 +70,10 @@ public String getName() {
return OperatorType.BIT_OR.getToken();
}
});

AviatorEvaluator.getInstance().addFunction(new StrContainsFunction());
AviatorEvaluator.getInstance().addFunction(new StrExistsFunction());
AviatorEvaluator.getInstance().addFunction(new StrMatchesFunction());
}

/**
Expand All @@ -75,12 +83,12 @@ private static class StrEqualFunction extends AbstractFunction {
@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
if (arg1 == null || arg2 == null) {
return AviatorBoolean.valueOf(false);
return AviatorBoolean.FALSE;
}
Object leftTmp = arg1.getValue(env);
Object rightTmp = arg2.getValue(env);
if (leftTmp == null || rightTmp == null) {
return AviatorBoolean.valueOf(false);
return AviatorBoolean.FALSE;
}
String left = String.valueOf(leftTmp);
String right = String.valueOf(rightTmp);
Expand All @@ -91,4 +99,76 @@ public String getName() {
return "equals";
}
}

/**
* 自定义aviator判断字符串1是否包含字符串2 (case-insensitive)
*/
private static class StrContainsFunction extends AbstractFunction {
@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
if (arg1 == null || arg2 == null) {
return AviatorBoolean.FALSE;
}
Object leftTmp = arg1.getValue(env);
Object rightTmp = arg2.getValue(env);
if (leftTmp == null || rightTmp == null) {
return AviatorBoolean.FALSE;
}
String left = String.valueOf(leftTmp);
String right = String.valueOf(rightTmp);
return AviatorBoolean.valueOf(StringUtils.containsIgnoreCase(left, right));
}
@Override
public String getName() {
return "contains";
}
}

/**
* 自定义aviator判断环境中是否存在字符串
*/
private static class StrExistsFunction extends AbstractFunction {
@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg) {
if (arg == null) {
return AviatorBoolean.FALSE;
}
Object keyTmp = arg.getValue(env);
if (keyTmp == null) {
return AviatorBoolean.FALSE;
}
String key = String.valueOf(keyTmp);
return AviatorBoolean.valueOf(env.containsKey(key));
}
@Override
public String getName() {
return "exists";
}
}

/**
* 自定义aviator判断字符串是否匹配regex
* - regex需要加上""或者''
*/
private static class StrMatchesFunction extends AbstractFunction {
@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
if (arg1 == null || arg2 == null) {
return AviatorBoolean.FALSE;
}
Object strTmp = arg1.getValue(env);
Object regexTmp = arg2.getValue(env);
if (strTmp == null || regexTmp == null) {
return AviatorBoolean.FALSE;
}
String str = String.valueOf(strTmp);
String regex = String.valueOf(regexTmp);
boolean isMatch = Pattern.compile(regex).matcher(str).matches();
return AviatorBoolean.valueOf(isMatch);
}
@Override
public String getName() {
return "matches";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package org.dromara.hertzbeat.common.config;

import com.googlecode.aviator.AviatorEvaluator;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import java.util.HashMap;
import java.util.Map;

/**
*
*
*/
class AviatorConfigurationTest {

@BeforeAll
static void setUp() {
AviatorConfiguration aviatorConfig = new AviatorConfiguration();
aviatorConfig.configAviatorEvaluator();
}

@Test
void testCustomStringFunctions() {
Map<String, Object> env = new HashMap<>();
env.put("k1", "Intel");
env.put("k2", "intel");
env.put("k3", "Ubuntu 18.04.6 LTS");
env.put("k4", "ubuntu");
env.put("k5", "Ubntu");
env.put("k6", null);

// test StrEqualFunction
String expr1 = "equals(k1,k2)"; // case-insensitive
Boolean res1 = (Boolean) AviatorEvaluator.compile(expr1).execute(env);
Assertions.assertTrue(res1);

String expr2 = "equals(k1,k3)";
Boolean res2 = (Boolean) AviatorEvaluator.compile(expr2).execute(env);
Assertions.assertFalse(res2);

// test StrContainsFunction
String expr3 = "contains(k3,k4)"; // case-insensitive
Boolean res3 = (Boolean) AviatorEvaluator.compile(expr3).execute(env);
Assertions.assertTrue(res3);

String expr4 = "contains(k4,k3)";
Boolean res4 = (Boolean) AviatorEvaluator.compile(expr4).execute(env);
Assertions.assertFalse(res4);

String expr5 = "contains(k3,k5)"; // subsequence
Boolean res5 = (Boolean) AviatorEvaluator.compile(expr5).execute(env);
Assertions.assertFalse(res5);

// test StrExistsFunction
String expr6 = "exists('DNE_Key1')";
Boolean res6 = (Boolean) AviatorEvaluator.compile(expr6).execute(env);
Assertions.assertFalse(res6);

String expr7 = "exists('k6')";
Boolean res7 = (Boolean) AviatorEvaluator.compile(expr7).execute(env);
Assertions.assertTrue(res7);

// test StrMatchesFunction
String regex1 = "'^[a-zA-Z0-9]+$'"; // only alphanumeric
String expr8 = "matches(k6," + regex1 + ")";
env.put("k6", "Ubntu50681269");
Boolean res8 = (Boolean) AviatorEvaluator.compile(expr8).execute(env);
Assertions.assertTrue(res8);
env.put("k6", "Ubnt_u50681269");
Boolean res9 = (Boolean) AviatorEvaluator.compile(expr8).execute(env);
Assertions.assertFalse(res9);

String regex2 = "'^Ubuntu.*'"; // starts with
String expr9 = "matches(k3," + regex2 + ")";
Boolean res10 = (Boolean) AviatorEvaluator.compile(expr9).execute(env);
Assertions.assertTrue(res10);
env.put("k3", "Ubunt_u50681269");
Boolean res11 = (Boolean) AviatorEvaluator.compile(expr9).execute(env);
Assertions.assertFalse(res11);

String regex3 = "\"^\\\\[LOG\\\\].*error$\""; // starts & ends with
String expr10 = "matches(k7," + regex3 + ")";
env.put("k7", "[LOG] detected system error");
Boolean res12 = (Boolean) AviatorEvaluator.compile(expr10).execute(env);
Assertions.assertTrue(res12);
env.put("k7", "[LOG detected system error");
Boolean res13 = (Boolean) AviatorEvaluator.compile(expr10).execute(env);
Assertions.assertFalse(res13);
}
}

0 comments on commit aaaccf0

Please sign in to comment.