/** * 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.mapping.form.evaluator.internal; import com.liferay.dynamic.data.mapping.data.provider.DDMDataProviderInvoker; 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.form.evaluator.DDMFormEvaluationException; import com.liferay.dynamic.data.mapping.form.evaluator.DDMFormEvaluationResult; import com.liferay.dynamic.data.mapping.form.evaluator.DDMFormEvaluatorContext; import com.liferay.dynamic.data.mapping.form.evaluator.DDMFormFieldEvaluationResult; import com.liferay.dynamic.data.mapping.form.evaluator.internal.functions.AllFunction; import com.liferay.dynamic.data.mapping.form.evaluator.internal.functions.BelongsToRoleFunction; import com.liferay.dynamic.data.mapping.form.evaluator.internal.functions.CallFunction; import com.liferay.dynamic.data.mapping.form.evaluator.internal.functions.GetPropertyFunction; import com.liferay.dynamic.data.mapping.form.evaluator.internal.functions.JumpPageFunction; import com.liferay.dynamic.data.mapping.form.evaluator.internal.functions.SetEnabledFunction; import com.liferay.dynamic.data.mapping.form.evaluator.internal.functions.SetInvalidFunction; import com.liferay.dynamic.data.mapping.form.evaluator.internal.functions.SetPropertyFunction; import com.liferay.dynamic.data.mapping.model.DDMForm; import com.liferay.dynamic.data.mapping.model.DDMFormField; import com.liferay.dynamic.data.mapping.model.DDMFormFieldValidation; import com.liferay.dynamic.data.mapping.model.DDMFormRule; import com.liferay.dynamic.data.mapping.model.Value; import com.liferay.dynamic.data.mapping.storage.DDMFormFieldValue; import com.liferay.dynamic.data.mapping.storage.DDMFormValues; import com.liferay.dynamic.data.mapping.storage.FieldConstants; import com.liferay.portal.kernel.json.JSONArray; import com.liferay.portal.kernel.json.JSONException; import com.liferay.portal.kernel.json.JSONFactory; import com.liferay.portal.kernel.language.LanguageUtil; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.service.RoleLocalService; import com.liferay.portal.kernel.service.UserGroupRoleLocalService; import com.liferay.portal.kernel.service.UserLocalService; import com.liferay.portal.kernel.util.AggregateResourceBundle; import com.liferay.portal.kernel.util.GetterUtil; import com.liferay.portal.kernel.util.ListUtil; import com.liferay.portal.kernel.util.ResourceBundleLoader; import com.liferay.portal.kernel.util.ResourceBundleLoaderUtil; import com.liferay.portal.kernel.util.ResourceBundleUtil; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.kernel.util.Validator; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.ResourceBundle; import java.util.Set; import javax.servlet.http.HttpServletRequest; /** * @author Leonardo Barros */ public class DDMFormEvaluatorHelper { public DDMFormEvaluatorHelper( DDMDataProviderInvoker ddmDataProviderInvoker, DDMExpressionFactory ddmExpressionFactory, DDMFormEvaluatorContext ddmFormEvaluatorContext, JSONFactory jsonFactory, RoleLocalService roleLocalService, UserGroupRoleLocalService userGroupRoleLocalService, UserLocalService userLocalService) { _ddmDataProviderInvoker = ddmDataProviderInvoker; _ddmExpressionFactory = ddmExpressionFactory; _jsonFactory = jsonFactory; _roleLocalService = roleLocalService; _userGroupRoleLocalService = userGroupRoleLocalService; _userLocalService = userLocalService; _ddmForm = ddmFormEvaluatorContext.getDDMForm(); _ddmFormFieldsMap = _ddmForm.getDDMFormFieldsMap(true); _groupId = ddmFormEvaluatorContext.getProperty("groupId"); _locale = ddmFormEvaluatorContext.getLocale(); _request = ddmFormEvaluatorContext.getProperty("request"); createDDMFormFieldValues(ddmFormEvaluatorContext.getDDMFormValues()); createDDMFormFieldRuleEvaluationResultsMap(); _resourceBundle = createResourceBundle(); registerDDMExpressionCustomFunctions(); } public DDMFormEvaluationResult evaluate() throws DDMFormEvaluationException { for (DDMFormRule ddmFormRule : _ddmForm.getDDMFormRules()) { evaluateDDMFormRule(ddmFormRule); } DDMFormEvaluationResult ddmFormEvaluationResult = new DDMFormEvaluationResult(); List<DDMFormFieldEvaluationResult> ddmFormFieldEvaluationResults = getDDMFormFieldEvaluationResults(); setDDMFormFieldEvaluationResultsValidation( ddmFormFieldEvaluationResults); ddmFormEvaluationResult.setDDMFormFieldEvaluationResults( ddmFormFieldEvaluationResults); Set<Integer> disabledPagesIndexes = getDisabledPagesIndexes(); ddmFormEvaluationResult.setDisabledPagesIndexes(disabledPagesIndexes); return ddmFormEvaluationResult; } protected DDMFormFieldEvaluationResult createDDMFormFieldEvaluationResult( DDMFormField ddmFormField, DDMFormFieldValue ddmFormFieldValue) { DDMFormFieldEvaluationResult ddmFormFieldEvaluationResult = new DDMFormFieldEvaluationResult( ddmFormField.getName(), ddmFormFieldValue.getInstanceId()); setDDMFormFieldEvaluationResultDataType( ddmFormField, ddmFormFieldEvaluationResult); setDDMFormFieldEvaluationResultReadOnly( ddmFormFieldEvaluationResult, ddmFormField); setDDMFormFieldEvaluationResultRequired( ddmFormFieldEvaluationResult, ddmFormField); setDDMFormFieldEvaluationResultVisibility( ddmFormFieldEvaluationResult, ddmFormField, ddmFormFieldValue); setDDMFormFieldEvaluationResultValidation( ddmFormFieldEvaluationResult, ddmFormField, ddmFormFieldValue); String type = ddmFormField.getType(); String valueString = getValueString(ddmFormFieldValue.getValue(), type); if (Objects.equals(type, "validation")) { ddmFormFieldEvaluationResult.setValue(valueString); return ddmFormFieldEvaluationResult; } Object value = FieldConstants.getSerializable( ddmFormField.getDataType(), valueString); ddmFormFieldEvaluationResult.setValue(value); return ddmFormFieldEvaluationResult; } protected void createDDMFormFieldRuleEvaluationResultsMap() { Map<String, DDMFormField> ddmFormFieldMap = _ddmForm.getDDMFormFieldsMap(true); for (DDMFormField ddmFormField : ddmFormFieldMap.values()) { createDDMFormFieldRuleEvaluationResultsMap(ddmFormField); } } protected void createDDMFormFieldRuleEvaluationResultsMap( DDMFormField ddmFormField) { List<DDMFormFieldEvaluationResult> ddmFormFieldEvaluationResultInstances = new ArrayList<>(); List<DDMFormFieldValue> ddmFormFieldValues = _ddmFormFieldValuesMap.get( ddmFormField.getName()); for (DDMFormFieldValue ddmFormFieldValue : ddmFormFieldValues) { DDMFormFieldEvaluationResult ddmFormFieldEvaluationResult = createDDMFormFieldEvaluationResult( ddmFormField, ddmFormFieldValue); ddmFormFieldEvaluationResultInstances.add( ddmFormFieldEvaluationResult); for (DDMFormFieldValue nestedDDMFormFieldValue : ddmFormFieldValue.getNestedDDMFormFieldValues()) { DDMFormField nestedDDMFormField = nestedDDMFormFieldValue.getDDMFormField(); ddmFormFieldEvaluationResult = createDDMFormFieldEvaluationResult( nestedDDMFormField, nestedDDMFormFieldValue); ddmFormFieldEvaluationResultInstances.add( ddmFormFieldEvaluationResult); } } _ddmFormFieldEvaluationResultsMap.put( ddmFormField.getName(), ddmFormFieldEvaluationResultInstances); } protected void createDDMFormFieldValues(DDMFormValues ddmFormValues) { List<DDMFormFieldValue> ddmFormFieldValues = ddmFormValues.getDDMFormFieldValues(); for (DDMFormFieldValue ddmFormFieldValue : ddmFormFieldValues) { populateDDMFormFieldValues(ddmFormFieldValue); } } protected ResourceBundle createResourceBundle() { ResourceBundleLoader portalResourceBundleLoader = ResourceBundleLoaderUtil.getPortalResourceBundleLoader(); ResourceBundle portalResourceBundle = portalResourceBundleLoader.loadResourceBundle(_locale); ResourceBundle portletResourceBundle = ResourceBundleUtil.getBundle( "content.Language", _locale, getClass()); return new AggregateResourceBundle( portletResourceBundle, portalResourceBundle); } protected void evaluateDDMFormRule(DDMFormRule ddmFormRule) throws DDMFormEvaluationException { DDMFormRuleEvaluator ddmFormRuleEvaluator = new DDMFormRuleEvaluator( ddmFormRule, _ddmExpressionFactory, _ddmExpressionFunctionRegistry); ddmFormRuleEvaluator.evaluate(); } protected List<DDMFormFieldEvaluationResult> getDDMFormFieldEvaluationResults() { List<DDMFormFieldEvaluationResult> ddmFormFieldEvaluationResults = new ArrayList<>(); for (List<DDMFormFieldEvaluationResult> ddmFormFieldEvaluationResultInstances : _ddmFormFieldEvaluationResultsMap.values()) { ddmFormFieldEvaluationResults.addAll( ddmFormFieldEvaluationResultInstances); } return ddmFormFieldEvaluationResults; } protected String getDDMFormFieldValidationErrorMessage( DDMFormFieldValidation ddmFormFieldValidation) { String errorMessage = ddmFormFieldValidation.getErrorMessage(); if (Validator.isNotNull(errorMessage)) { return errorMessage; } return LanguageUtil.get(_resourceBundle, "this-field-is-invalid"); } protected DDMFormFieldValue getDDMFormFieldValue( String ddmFormFieldName, String instanceId) { List<DDMFormFieldValue> ddmFormFieldValues = _ddmFormFieldValuesMap.get( ddmFormFieldName); if (ListUtil.isEmpty(ddmFormFieldValues)) { return null; } for (DDMFormFieldValue ddmFormFieldValue : ddmFormFieldValues) { if (instanceId.equals(ddmFormFieldValue.getInstanceId())) { return ddmFormFieldValue; } for (DDMFormFieldValue nestedDDMFormFieldValue : ddmFormFieldValue.getNestedDDMFormFieldValues()) { if (instanceId.equals( nestedDDMFormFieldValue.getInstanceId())) { return nestedDDMFormFieldValue; } } } return null; } protected boolean getDefaultBooleanPropertyState( String functionName, String ddmFormFieldName, boolean defaultValue) { String setFieldAction = String.format( "%s('%s', true)", functionName, ddmFormFieldName); for (DDMFormRule ddmFormRule : _ddmForm.getDDMFormRules()) { for (String action : ddmFormRule.getActions()) { if (Objects.equals(setFieldAction, action)) { return false; } } } return defaultValue; } protected Set<Integer> getDisabledPagesIndexes() { Set<Integer> disabledPagesIndexes = new HashSet<>(); for (Map.Entry<Integer, Integer> entry : _pageFlow.entrySet()) { int fromPageIndex = entry.getKey(); int toPageIndex = entry.getValue(); for (int i = fromPageIndex + 1; i < toPageIndex; i++) { disabledPagesIndexes.add(i); } } return disabledPagesIndexes; } protected String getJSONArrayValueString(String valueString) { try { JSONArray jsonArray = _jsonFactory.createJSONArray(valueString); return jsonArray.getString(0); } catch (JSONException jsone) { // LPS-52675 if (_log.isDebugEnabled()) { _log.debug(jsone, jsone); } return valueString; } } protected String getValueString(Value value, String type) { if (value == null) { return null; } String valueString = GetterUtil.getString(value.getString(_locale)); if (type.equals("select") || type.equals("radio")) { valueString = getJSONArrayValueString(valueString); } return valueString; } protected boolean isDDMFormFieldValueEmpty( DDMFormField ddmFormField, DDMFormFieldValue ddmFormFieldValue) { Value value = ddmFormFieldValue.getValue(); if (value == null) { return true; } String valueString = value.getString(_locale); if (Validator.isNull(StringUtil.trim(valueString))) { return true; } String dataType = ddmFormField.getDataType(); if (Objects.equals(dataType, "boolean") && Objects.equals(valueString, "false")) { return true; } return false; } protected void populateDDMFormFieldValues( DDMFormFieldValue ddmFormFieldValue) { List<DDMFormFieldValue> ddmFormFieldValues = _ddmFormFieldValuesMap.get( ddmFormFieldValue.getName()); if (ddmFormFieldValues == null) { ddmFormFieldValues = new ArrayList<>(); _ddmFormFieldValuesMap.put( ddmFormFieldValue.getName(), ddmFormFieldValues); } ddmFormFieldValues.add(ddmFormFieldValue); for (DDMFormFieldValue nestedDDMFormFieldValue : ddmFormFieldValue.getNestedDDMFormFieldValues()) { populateDDMFormFieldValues(nestedDDMFormFieldValue); } } protected void registerDDMExpressionCustomFunctions() { _ddmExpressionFunctionRegistry.registerDDMExpressionFunction( "all", new AllFunction( _ddmExpressionFactory, _ddmExpressionFunctionRegistry)); _ddmExpressionFunctionRegistry.registerDDMExpressionFunction( "belongsTo", new BelongsToRoleFunction( _request, _groupId, _roleLocalService, _userGroupRoleLocalService, _userLocalService)); _ddmExpressionFunctionRegistry.registerDDMExpressionFunction( "calculate", new SetPropertyFunction( _ddmFormFieldEvaluationResultsMap, "value")); _ddmExpressionFunctionRegistry.registerDDMExpressionFunction( "call", new CallFunction( _ddmDataProviderInvoker, _ddmFormFieldEvaluationResultsMap, _request, _jsonFactory)); _ddmExpressionFunctionRegistry.registerDDMExpressionFunction( "getValue", new GetPropertyFunction( _ddmFormFieldEvaluationResultsMap, "value")); _ddmExpressionFunctionRegistry.registerDDMExpressionFunction( "jumpPage", new JumpPageFunction(_pageFlow)); _ddmExpressionFunctionRegistry.registerDDMExpressionFunction( "setEnabled", new SetEnabledFunction(_ddmFormFieldEvaluationResultsMap)); _ddmExpressionFunctionRegistry.registerDDMExpressionFunction( "setInvalid", new SetInvalidFunction(_ddmFormFieldEvaluationResultsMap)); _ddmExpressionFunctionRegistry.registerDDMExpressionFunction( "setRequired", new SetPropertyFunction( _ddmFormFieldEvaluationResultsMap, "required")); _ddmExpressionFunctionRegistry.registerDDMExpressionFunction( "setValue", new SetPropertyFunction( _ddmFormFieldEvaluationResultsMap, "value")); _ddmExpressionFunctionRegistry.registerDDMExpressionFunction( "setVisible", new SetPropertyFunction( _ddmFormFieldEvaluationResultsMap, "visible")); } protected void setDDMExpressionVariables( DDMExpression<Boolean> ddmExpression, DDMFormFieldValue ddmFormFieldValue) throws DDMExpressionException { for (String ddmFormFieldName : _ddmFormFieldValuesMap.keySet()) { DDMFormField ddmFormField = _ddmFormFieldsMap.get(ddmFormFieldName); List<DDMFormFieldValue> ddmFormFieldValues = _ddmFormFieldValuesMap.get(ddmFormFieldName); DDMFormFieldValue selectedDDMFormFieldValue = ddmFormFieldValues.get(0); if (ddmFormFieldName.equals(ddmFormFieldValue.getName())) { selectedDDMFormFieldValue = ddmFormFieldValue; } String valueString = getValueString( selectedDDMFormFieldValue.getValue(), ddmFormField.getType()); String dataType = ddmFormField.getDataType(); if (FieldConstants.isNumericType(ddmFormField.getDataType())) { if (Validator.isNotNull(valueString)) { ddmExpression.setDoubleVariableValue( ddmFormFieldName, GetterUtil.getDouble(valueString)); } } else if (dataType.equals(FieldConstants.BOOLEAN)) { if (Validator.isNotNull(valueString)) { ddmExpression.setBooleanVariableValue( ddmFormFieldName, GetterUtil.getBoolean(valueString)); } } else { ddmExpression.setStringVariableValue( ddmFormFieldName, valueString); } } } protected void setDDMFormFieldEvaluationResultDataType( DDMFormField ddmFormField, DDMFormFieldEvaluationResult ddmFormFieldEvaluationResult) { ddmFormFieldEvaluationResult.setProperty( "dataType", ddmFormField.getDataType()); } protected void setDDMFormFieldEvaluationResultReadOnly( DDMFormFieldEvaluationResult ddmFormFieldEvaluationResult, DDMFormField ddmFormField) { boolean enabled = getDefaultBooleanPropertyState( "setEnabled", ddmFormField.getName(), !ddmFormField.isReadOnly()); ddmFormFieldEvaluationResult.setReadOnly(!enabled); } protected void setDDMFormFieldEvaluationResultRequired( DDMFormFieldEvaluationResult ddmFormFieldEvaluationResult, DDMFormField ddmFormField) { boolean required = getDefaultBooleanPropertyState( "setRequired", ddmFormField.getName(), ddmFormField.isRequired()); ddmFormFieldEvaluationResult.setRequired(required); } protected void setDDMFormFieldEvaluationResultsValidation( List<DDMFormFieldEvaluationResult> ddmFormFieldEvaluationResults) { for (DDMFormFieldEvaluationResult ddmFormFieldEvaluationResult : ddmFormFieldEvaluationResults) { String ddmFormFieldName = ddmFormFieldEvaluationResult.getName(); DDMFormFieldValue ddmFormFieldValue = getDDMFormFieldValue( ddmFormFieldName, ddmFormFieldEvaluationResult.getInstanceId()); setDDMFormFieldEvaluationResultValidation( ddmFormFieldEvaluationResult, _ddmFormFieldsMap.get(ddmFormFieldName), ddmFormFieldValue); } } protected void setDDMFormFieldEvaluationResultValidation( DDMFormFieldEvaluationResult ddmFormFieldEvaluationResult, DDMFormField ddmFormField, DDMFormFieldValue ddmFormFieldValue) { boolean required = ddmFormFieldEvaluationResult.isRequired(); boolean emptyValue = isDDMFormFieldValueEmpty( ddmFormField, ddmFormFieldValue); if (!required && emptyValue) { return; } boolean visible = ddmFormFieldEvaluationResult.isVisible(); if (required && visible && emptyValue) { ddmFormFieldEvaluationResult.setErrorMessage( LanguageUtil.get(_resourceBundle, "this-field-is-required")); ddmFormFieldEvaluationResult.setValid(false); return; } DDMFormFieldValidation ddmFormFieldValidation = ddmFormField.getDDMFormFieldValidation(); if (ddmFormFieldValidation == null) { return; } String validationExpression = ddmFormFieldValidation.getExpression(); if (Validator.isNull(validationExpression)) { return; } try { DDMExpression<Boolean> ddmExpression = _ddmExpressionFactory.createBooleanDDMExpression( validationExpression); setDDMExpressionVariables(ddmExpression, ddmFormFieldValue); boolean valid = ddmExpression.evaluate(); if (!valid) { ddmFormFieldEvaluationResult.setErrorMessage( getDDMFormFieldValidationErrorMessage( ddmFormFieldValidation)); ddmFormFieldEvaluationResult.setValid(false); } } catch (DDMExpressionException ddmee) { if (_log.isDebugEnabled()) { _log.debug( String.format( "Error processing validation expression \"%s\" for " + "field \"%s\"", validationExpression, ddmFormField.getName()), ddmee); } } } protected void setDDMFormFieldEvaluationResultVisibility( DDMFormFieldEvaluationResult ddmFormFieldEvaluationResult, DDMFormField ddmFormField, DDMFormFieldValue ddmFormFieldValue) { String visibilityExpression = ddmFormField.getVisibilityExpression(); if (Validator.isNull(visibilityExpression) || StringUtil.equalsIgnoreCase(visibilityExpression, "TRUE")) { boolean defaultState = getDefaultBooleanPropertyState( "setVisible", ddmFormField.getName(), true); ddmFormFieldEvaluationResult.setVisible(defaultState); return; } try { DDMExpression<Boolean> ddmExpression = _ddmExpressionFactory.createBooleanDDMExpression( visibilityExpression); setDDMExpressionVariables(ddmExpression, ddmFormFieldValue); ddmFormFieldEvaluationResult.setVisible(ddmExpression.evaluate()); } catch (DDMExpressionException ddmee) { if (_log.isDebugEnabled()) { _log.debug( String.format( "Error processing visibility expression \"%s\" for " + "field \"%s\"", visibilityExpression, ddmFormField.getName()), ddmee); } } } private static final Log _log = LogFactoryUtil.getLog( DDMFormEvaluatorHelper.class); private final DDMDataProviderInvoker _ddmDataProviderInvoker; private final DDMExpressionFactory _ddmExpressionFactory; private final DDMExpressionFunctionRegistry _ddmExpressionFunctionRegistry = new DDMExpressionFunctionRegistry(); private final DDMForm _ddmForm; private final Map<String, List<DDMFormFieldEvaluationResult>> _ddmFormFieldEvaluationResultsMap = new HashMap<>(); private final Map<String, DDMFormField> _ddmFormFieldsMap; private final Map<String, List<DDMFormFieldValue>> _ddmFormFieldValuesMap = new LinkedHashMap<>(); private final long _groupId; private final JSONFactory _jsonFactory; private final Locale _locale; private final Map<Integer, Integer> _pageFlow = new HashMap<>(); private final HttpServletRequest _request; private final ResourceBundle _resourceBundle; private final RoleLocalService _roleLocalService; private final UserGroupRoleLocalService _userGroupRoleLocalService; private final UserLocalService _userLocalService; }