forked from fanruan/design
Browse Source
* commit '7dbe84f30d967aad6154306843992104415e5e62': REPORT-59919 && REPORT-59921 && REPORT-59922 REPORT-59919 && REPORT-59921 && REPORT-59922 REPORT-54887 公式编辑器优化一期 1.提供一个公式检验的接口,返回提示信息。research/11.0
superman
3 years ago
4 changed files with 185 additions and 91 deletions
@ -0,0 +1,88 @@ |
|||||||
|
package com.fr.design.formula; |
||||||
|
|
||||||
|
import com.fr.design.i18n.Toolkit; |
||||||
|
import com.fr.log.FineLoggerFactory; |
||||||
|
import com.fr.parser.FRLexer; |
||||||
|
import com.fr.parser.FRParser; |
||||||
|
import com.fr.script.checker.FunctionCheckerDispatcher; |
||||||
|
import com.fr.script.checker.exception.ConditionCheckWrongException; |
||||||
|
import com.fr.script.checker.exception.FunctionCheckWrongException; |
||||||
|
import com.fr.script.rules.FunctionParameterType; |
||||||
|
import com.fr.script.rules.FunctionRule; |
||||||
|
import com.fr.stable.StringUtils; |
||||||
|
import com.fr.stable.script.Expression; |
||||||
|
import com.fr.stable.script.Node; |
||||||
|
|
||||||
|
import java.io.StringReader; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Hoky |
||||||
|
* @date 2021/9/28 |
||||||
|
*/ |
||||||
|
public class FormulaChecker { |
||||||
|
private static final String VALID_FORMULA = Toolkit.i18nText("Fine-Design_Basic_FormulaD_Valid_Formula"); |
||||||
|
private static final String INVALID_FORMULA = Toolkit.i18nText("Fine-Design_Basic_FormulaD_Invalid_Formula"); |
||||||
|
public static final String COLON = ":"; |
||||||
|
|
||||||
|
public static String check(String formulaText) { |
||||||
|
StringReader in = new StringReader(formulaText); |
||||||
|
|
||||||
|
FRLexer lexer = new FRLexer(in); |
||||||
|
FRParser parser = new FRParser(lexer); |
||||||
|
|
||||||
|
try { |
||||||
|
Expression expression = parser.parse(); |
||||||
|
Node node = expression.getConditionalExpression(); |
||||||
|
return FunctionCheckerDispatcher.getInstance() |
||||||
|
.getFunctionChecker(node) |
||||||
|
.checkFunction(node) ? VALID_FORMULA : INVALID_FORMULA; |
||||||
|
} catch (ConditionCheckWrongException cce) { |
||||||
|
String functionName = cce.getFunctionName(); |
||||||
|
return functionName + Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Condition_Tips") + COLON; |
||||||
|
} catch (FunctionCheckWrongException ce) { |
||||||
|
List<FunctionRule> rules = ce.getRules(); |
||||||
|
String functionName = ce.getFunctionName(); |
||||||
|
StringBuilder errorMsg = new StringBuilder(functionName + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Error_Tips") + COLON); |
||||||
|
for (int i = 0; i < rules.size(); i++) { |
||||||
|
errorMsg.append("("); |
||||||
|
if (rules.get(i).getParameterList().isEmpty()) { |
||||||
|
errorMsg.append(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_No_Param")); |
||||||
|
} |
||||||
|
for (FunctionParameterType functionParameterType : rules.get(i).getParameterList()) { |
||||||
|
errorMsg.append(getTypeString(functionParameterType)).append(","); |
||||||
|
} |
||||||
|
if (",".equals(errorMsg.charAt(errorMsg.length() - 1) + "")) { |
||||||
|
errorMsg.deleteCharAt(errorMsg.length() - 1); |
||||||
|
} |
||||||
|
errorMsg.append(")"); |
||||||
|
if (i != rules.size() - 1) { |
||||||
|
errorMsg.append(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Or")); |
||||||
|
} |
||||||
|
} |
||||||
|
return errorMsg.toString(); |
||||||
|
} catch (Exception e) { |
||||||
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||||
|
return INVALID_FORMULA; |
||||||
|
// alex:继续往下面走,expression为null时告知不合法公式
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static String getTypeString(FunctionParameterType type) { |
||||||
|
switch (type) { |
||||||
|
case NUMBER: |
||||||
|
return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_Number"); |
||||||
|
case STRING: |
||||||
|
return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_String"); |
||||||
|
case ANY: |
||||||
|
return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_Any"); |
||||||
|
case DATE: |
||||||
|
return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_Date"); |
||||||
|
case BOOLEAN: |
||||||
|
return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_Boolean"); |
||||||
|
case ARRAY: |
||||||
|
return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_Array"); |
||||||
|
} |
||||||
|
return StringUtils.EMPTY; |
||||||
|
} |
||||||
|
} |
@ -1,27 +1,97 @@ |
|||||||
package com.fr.design.mainframe.authority; |
package com.fr.design.mainframe.authority; |
||||||
|
|
||||||
import com.fr.base.Formula; |
import com.fr.base.Formula; |
||||||
|
import com.fr.general.ComparatorUtils; |
||||||
|
import com.fr.parser.FunctionCall; |
||||||
|
import com.fr.parser.StringLiteral; |
||||||
|
import com.fr.script.Calculator; |
||||||
|
import com.fr.stable.script.Node; |
||||||
import org.jetbrains.annotations.Nullable; |
import org.jetbrains.annotations.Nullable; |
||||||
|
|
||||||
import java.util.Arrays; |
|
||||||
import java.util.HashSet; |
import java.util.HashSet; |
||||||
import java.util.Set; |
import java.util.Set; |
||||||
import java.util.regex.Matcher; |
|
||||||
import java.util.regex.Pattern; |
|
||||||
|
|
||||||
public class FormulaAuthorityChecker extends ElementAuthorityChecker<Formula> { |
public class FormulaAuthorityChecker extends ElementAuthorityChecker<Formula> { |
||||||
private static final Pattern FORMULA_PATTERN = Pattern.compile("^=SQL\\(\"(.+?)\","); |
private static final Set<FormulaParser> CONNECTION_NAME_FORMULA_PARSER = new HashSet<>(); |
||||||
|
private static final Set<FormulaParser> DATASET_NAME_FORMULA_PARSER = new HashSet<>(); |
||||||
|
|
||||||
|
static { |
||||||
|
CONNECTION_NAME_FORMULA_PARSER.add(new FormulaParser("SQL", 0)); |
||||||
|
DATASET_NAME_FORMULA_PARSER.add(new FormulaParser("VALUE", 0)); |
||||||
|
} |
||||||
|
|
||||||
@Override |
@Override |
||||||
@Nullable |
@Nullable |
||||||
public Set<String> getNoAuthConnectionNames(Formula formula, Set<String> authConnectionNames) { |
public Set<String> getNoAuthConnectionNames(Formula formula, Set<String> authConnectionNames) { |
||||||
String content = formula.getContent(); |
return getNoAuthNames(formula, CONNECTION_NAME_FORMULA_PARSER, authConnectionNames); |
||||||
Matcher matcher = FORMULA_PATTERN.matcher(content); |
} |
||||||
if (matcher.find()) { |
|
||||||
if (!authConnectionNames.contains(matcher.group(1))) { |
|
||||||
return new HashSet<>(Arrays.asList(matcher.group(1))); |
@Override |
||||||
|
@Nullable |
||||||
|
Set<String> getNoAuthDatasetNames(Formula formula, Set<String> authDatasetNames) { |
||||||
|
return getNoAuthNames(formula, DATASET_NAME_FORMULA_PARSER, authDatasetNames); |
||||||
|
} |
||||||
|
|
||||||
|
private Set<String> getNoAuthNames(Formula formula, Set<FormulaParser> formulaParsers, Set<String> authNames) { |
||||||
|
Set<String> noAuthNames = new HashSet<>(); |
||||||
|
try { |
||||||
|
FunctionCall functionCall = (FunctionCall) Calculator.createCalculator().parse(formula.getContent()).getConditionalExpression(); |
||||||
|
handleNoAuthNames(functionCall, formulaParsers, authNames, noAuthNames); |
||||||
|
} catch (Exception ignore) { |
||||||
|
|
||||||
|
} finally { |
||||||
|
return noAuthNames; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void handleNoAuthNames(FunctionCall functionCall, Set<FormulaParser> formulaParsers, Set<String> authNames, Set<String> noAuthNames) { |
||||||
|
for (FormulaParser formulaPattern : formulaParsers) { |
||||||
|
String noAuthName = formulaPattern.getNoAuthName(functionCall, authNames); |
||||||
|
if (noAuthName != null) { |
||||||
|
noAuthNames.add(noAuthName); |
||||||
|
} |
||||||
|
} |
||||||
|
Node[] nodes = functionCall.getArguments(); |
||||||
|
if (nodes != null) { |
||||||
|
for (int i = 0; i < nodes.length; i++) { |
||||||
|
Node node = nodes[i]; |
||||||
|
if (node instanceof FunctionCall) { |
||||||
|
handleNoAuthNames((FunctionCall) node, formulaParsers, authNames, noAuthNames); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
static class FormulaParser { |
||||||
|
//函数的名称
|
||||||
|
public String name; |
||||||
|
//要检测的位置
|
||||||
|
public int index; |
||||||
|
|
||||||
|
|
||||||
|
FormulaParser(String name, int index) { |
||||||
|
this.name = name; |
||||||
|
this.index = index; |
||||||
|
} |
||||||
|
|
||||||
|
String getNoAuthName(FunctionCall functionCall, Set<String> authNames) { |
||||||
|
if (functionCall.getName() != null && ComparatorUtils.equals(functionCall.getName().toUpperCase(), name)) { |
||||||
|
Node node = functionCall.getArguments()[index]; |
||||||
|
if (node instanceof StringLiteral) { |
||||||
|
String stringLiteral = node.toString(); |
||||||
|
if (stringLiteral.length() > 2) { |
||||||
|
String value = stringLiteral.substring(1, stringLiteral.length() - 1); |
||||||
|
if (!authNames.contains(value)) { |
||||||
|
return value; |
||||||
|
} |
||||||
|
} |
||||||
} |
} |
||||||
} |
} |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
|
} |
||||||
|
|
||||||
} |
} |
||||||
|
Loading…
Reference in new issue