/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library 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 Lesser General Public License for more
* details.
*/
package com.liferay.dynamic.data.lists.form.web.internal.converter;
import com.liferay.dynamic.data.lists.form.web.internal.converter.model.DDLFormRule;
import com.liferay.dynamic.data.lists.form.web.internal.converter.model.DDLFormRuleAction;
import com.liferay.dynamic.data.lists.form.web.internal.converter.model.DDLFormRuleCondition;
import com.liferay.dynamic.data.lists.form.web.internal.converter.model.DDLFormRuleCondition.Operand;
import com.liferay.dynamic.data.mapping.expression.DDMExpression;
import com.liferay.dynamic.data.mapping.expression.DDMExpressionException;
import com.liferay.dynamic.data.mapping.expression.DDMExpressionFactory;
import com.liferay.dynamic.data.mapping.expression.model.AndExpression;
import com.liferay.dynamic.data.mapping.expression.model.BinaryExpression;
import com.liferay.dynamic.data.mapping.expression.model.ComparisonExpression;
import com.liferay.dynamic.data.mapping.expression.model.Expression;
import com.liferay.dynamic.data.mapping.expression.model.ExpressionVisitor;
import com.liferay.dynamic.data.mapping.expression.model.FunctionCallExpression;
import com.liferay.dynamic.data.mapping.expression.model.NotExpression;
import com.liferay.dynamic.data.mapping.expression.model.OrExpression;
import com.liferay.dynamic.data.mapping.expression.model.Term;
import com.liferay.dynamic.data.mapping.model.DDMFormRule;
import com.liferay.portal.kernel.util.StringPool;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Stack;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* @author Leonardo Barros
* @author Marcellus Tavares
*/
@Component(immediate = true, service = DDMFormRuleToDDLFormRuleConverter.class)
public class DDMFormRuleToDDLFormRuleConverter {
public List<DDLFormRule> convert(List<DDMFormRule> ddmFormRules) {
List<DDLFormRule> ddlFormRules = new ArrayList<>();
for (DDMFormRule ddmFormRule : ddmFormRules) {
ddlFormRules.add(convertRule(ddmFormRule));
}
return ddlFormRules;
}
protected DDLFormRuleAction convertAction(String actionExpressionString) {
Expression actionExpression = createExpression(actionExpressionString);
ActionExpressionVisitor actionExpressionVisitor =
new ActionExpressionVisitor();
return (DDLFormRuleAction)actionExpression.accept(
actionExpressionVisitor);
}
protected DDLFormRule convertRule(DDMFormRule ddmFormRule) {
DDLFormRule ddlFormRule = new DDLFormRule();
setDDLFormRuleConditions(ddlFormRule, ddmFormRule.getCondition());
setDDLFormRuleActions(ddlFormRule, ddmFormRule.getActions());
return ddlFormRule;
}
protected Expression createExpression(String expressionString) {
try {
DDMExpression<Boolean> ddmExpression =
ddmExpressionFactory.createBooleanDDMExpression(
expressionString);
return ddmExpression.getModel();
}
catch (DDMExpressionException ddmee) {
throw new IllegalStateException(
String.format(
"Unable to parse expression \"%s\"", expressionString),
ddmee);
}
}
protected void setDDLFormRuleActions(
DDLFormRule ddlFormRule, List<String> actions) {
List<DDLFormRuleAction> ddlFormRuleActions = new ArrayList<>();
for (String action : actions) {
ddlFormRuleActions.add(convertAction(action));
}
ddlFormRule.setDDLFormRuleActions(ddlFormRuleActions);
}
protected void setDDLFormRuleConditions(
DDLFormRule ddlFormRule, String conditionExpressionString) {
Expression conditionExpression = createExpression(
conditionExpressionString);
ConditionExpressionVisitor conditionExpressionVisitor =
new ConditionExpressionVisitor();
conditionExpression.accept(conditionExpressionVisitor);
ddlFormRule.setDDLFormRuleConditions(
conditionExpressionVisitor.getConditions());
ddlFormRule.setLogicalOperator(
conditionExpressionVisitor.getLogicalOperator());
}
@Reference
protected DDMExpressionFactory ddmExpressionFactory;
protected static class ActionExpressionVisitor
extends ExpressionVisitor<Object> {
@Override
public Object visit(FunctionCallExpression functionCallExpression) {
String action = _functionToActionMap.get(
functionCallExpression.getFunctionName());
List<Expression> parameters =
functionCallExpression.getParameterExpressions();
return DDLFormRuleActionFactory.create(action, parameters, this);
}
@Override
public Object visit(Term term) {
return term.getValue();
}
protected <T> T doVisit(Expression expression) {
return (T)expression.accept(this);
}
private static final Map<String, String> _functionToActionMap =
new HashMap<>();
static {
_functionToActionMap.put("calculate", "calculate");
_functionToActionMap.put("call", "auto-fill");
_functionToActionMap.put("jumpPage", "jump-to-page");
_functionToActionMap.put("setEnabled", "enable");
_functionToActionMap.put("setInvalid", "invalidate");
_functionToActionMap.put("setRequired", "require");
_functionToActionMap.put("setVisible", "show");
}
}
private static class ConditionExpressionVisitor
extends ExpressionVisitor<Object> {
public List<DDLFormRuleCondition> getConditions() {
return _conditions;
}
public String getLogicalOperator() {
if (_andOperator) {
return "AND";
}
return "OR";
}
@Override
public Object visit(AndExpression andExpression) {
_andOperator = true;
return doVisitLogicalExpression(andExpression);
}
@Override
public Object visit(ComparisonExpression comparisonExpression) {
DDLFormRuleCondition.Operand leftOperand = doVisit(
comparisonExpression.getLeftOperandExpression());
DDLFormRuleCondition.Operand rightOperand = doVisit(
comparisonExpression.getRightOperandExpression());
DDLFormRuleCondition ddlFormRuleCondition =
new DDLFormRuleCondition(
_operatorMap.get(comparisonExpression.getOperator()),
Arrays.asList(leftOperand, rightOperand));
_conditions.push(ddlFormRuleCondition);
return _conditions;
}
@Override
public Object visit(FunctionCallExpression functionCallExpression) {
String functionName = functionCallExpression.getFunctionName();
List<Expression> parameterExpressions =
functionCallExpression.getParameterExpressions();
if (Objects.equals(functionName, "getValue")) {
DDLFormRuleCondition.Operand operand = doVisit(
parameterExpressions.get(0));
return new DDLFormRuleCondition.Operand(
"field", operand.getValue());
}
List<DDLFormRuleCondition.Operand> operands = new ArrayList<>();
for (Expression parameterExpression : parameterExpressions) {
operands.add(
(DDLFormRuleCondition.Operand)doVisit(parameterExpression));
}
_conditions.push(
createDDLFormRuleCondition(functionName, operands));
return _conditions;
}
@Override
public Object visit(NotExpression notExpression) {
doVisit(notExpression.getOperandExpression());
DDLFormRuleCondition condition = _conditions.peek();
String operator = condition.getOperator();
condition.setOperator("not-" + operator);
return _conditions;
}
@Override
public Object visit(OrExpression orExpression) {
_andOperator = false;
return doVisitLogicalExpression(orExpression);
}
@Override
public Object visit(Term term) {
return new DDLFormRuleCondition.Operand(
"constant", term.getValue());
}
protected DDLFormRuleCondition createBelongsToCondition(
String belongsToFunctionName, List<Operand> operands) {
List<Operand> belongsToOperands = new ArrayList<>();
Stream<Operand> operandsStream = operands.stream();
Stream<String> valuesStream = operandsStream.map(
operand -> operand.getValue());
belongsToOperands.add(
new Operand(
"list",
valuesStream.collect(
Collectors.joining(StringPool.COMMA))));
return new DDLFormRuleCondition(
belongsToFunctionName, belongsToOperands);
}
protected DDLFormRuleCondition createDDLFormRuleCondition(
String functionName, List<DDLFormRuleCondition.Operand> operands) {
String functionNameOperator = _functionNameOperatorMap.get(
functionName);
if (Objects.equals(functionNameOperator, "belongs-to")) {
return createBelongsToCondition(functionNameOperator, operands);
}
return new DDLFormRuleCondition(functionNameOperator, operands);
}
protected <T> T doVisit(Expression expression) {
return (T)expression.accept(this);
}
protected List<DDLFormRuleCondition> doVisitLogicalExpression(
BinaryExpression binaryExpression) {
Object o1 = doVisit(binaryExpression.getLeftOperandExpression());
Object o2 = doVisit(binaryExpression.getRightOperandExpression());
if (o1 instanceof DDLFormRuleCondition) {
_conditions.push((DDLFormRuleCondition)o1);
}
if (o2 instanceof DDLFormRuleCondition) {
_conditions.push((DDLFormRuleCondition)o2);
}
return _conditions;
}
private static final Map<String, String> _functionNameOperatorMap =
new HashMap<>();
private static final Map<String, String> _operatorMap = new HashMap<>();
static {
_operatorMap.put("<", "less-than");
_operatorMap.put("<=", "less-than-equals");
_operatorMap.put(">", "greater-than");
_operatorMap.put(">=", "greater-than-equals");
_functionNameOperatorMap.put("belongsTo", "belongs-to");
_functionNameOperatorMap.put("contains", "contains");
_functionNameOperatorMap.put("equals", "equals-to");
_functionNameOperatorMap.put("isEmpty", "is-empty");
}
private boolean _andOperator = true;
private final Stack<DDLFormRuleCondition> _conditions = new Stack<>();
}
}