diff --git a/android-json-form-wizard/build.gradle b/android-json-form-wizard/build.gradle index 26f1516eb..223b7447f 100644 --- a/android-json-form-wizard/build.gradle +++ b/android-json-form-wizard/build.gradle @@ -109,9 +109,13 @@ dependencies { implementation 'org.smartregister:opensrp-client-utils:0.0.6-SNAPSHOT' implementation 'androidx.test:core:1.4.0' - def easyRulesVersion = '3.4.0' - implementation "org.jeasy:easy-rules-core:$easyRulesVersion" - implementation "org.jeasy:easy-rules-mvel:$easyRulesVersion" + def easyRulesVersion = '4.1.2-SNAPSHOT' + implementation ("org.smartregister:easy-rules-core:$easyRulesVersion"){ + } + implementation ("org.smartregister:easy-rules-mvel:$easyRulesVersion") + { + exclude group: 'org.jeasy', module: 'easy-rules-core' + } implementation 'joda-time:joda-time:2.10.14' implementation 'com.google.code.gson:gson:2.9.0' diff --git a/android-json-form-wizard/src/main/assets/app.properties b/android-json-form-wizard/src/main/assets/app.properties index a2e8a9e3a..b9ebaae30 100644 --- a/android-json-form-wizard/src/main/assets/app.properties +++ b/android-json-form-wizard/src/main/assets/app.properties @@ -1,2 +1,3 @@ widget.datepicker.is.numeric=true -widget.value.translated=true \ No newline at end of file +widget.value.translated=true +easy_rule.v3.compatibility=true \ No newline at end of file diff --git a/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/activities/JsonFormActivity.java b/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/activities/JsonFormActivity.java index 42287b5d2..eba58e260 100644 --- a/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/activities/JsonFormActivity.java +++ b/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/activities/JsonFormActivity.java @@ -1,9 +1,5 @@ package com.vijay.jsonwizard.activities; -import static android.view.inputmethod.InputMethodManager.HIDE_NOT_ALWAYS; -import static com.vijay.jsonwizard.utils.FormUtils.getCheckboxValueJsonArray; -import static com.vijay.jsonwizard.utils.FormUtils.getCurrentCheckboxValues; - import android.Manifest; import android.annotation.SuppressLint; import android.app.AlertDialog; @@ -108,6 +104,10 @@ import timber.log.Timber; +import static android.view.inputmethod.InputMethodManager.HIDE_NOT_ALWAYS; +import static com.vijay.jsonwizard.utils.FormUtils.getCheckboxValueJsonArray; +import static com.vijay.jsonwizard.utils.FormUtils.getCurrentCheckboxValues; + public class JsonFormActivity extends JsonFormBaseActivity implements JsonApi { private final FormUtils formUtils = new FormUtils(); @@ -1427,7 +1427,14 @@ private Facts getEntries(String[] address, JSONObject object) throws JSONExcepti formObject.put(RuleConstant.IS_RULE_CHECK, true); formObject.put(RuleConstant.STEP, formObject.getString(RuleConstant.STEP)); - result.asMap().putAll(getValueFromAddressCore(formObject).asMap()); + if (Utils.enabledProperty(NativeFormsProperties.KEY.EASY_RULES_V3_COMPATIBILITY)) { + Facts resultFacts = getValueFromAddressCore(formObject); + + for (Map.Entry factEntry : resultFacts.asMap().entrySet()) { + result.put(factEntry.getKey(), factEntry.getValue()); + } + } + } result.put(RuleConstant.SELECTED_RULE, address[2]); @@ -1932,16 +1939,24 @@ private List getRules(String filename, String fieldKey, boolean readAllR StringBuilder conditionString = new StringBuilder(); conditionString.append(map.get(RuleConstant.CONDITION).toString()); + boolean backwardCompatibility = Utils.enabledProperty(NativeFormsProperties.KEY.EASY_RULES_V3_COMPATIBILITY); List fields = (List) map.get(RuleConstant.ACTIONS); + List newFields = new ArrayList<>(); if (fields != null) { for (String field : fields) { if (field.trim().startsWith(RuleConstant.CALCULATION) || field.trim().startsWith(RuleConstant.CONSTRAINT)) { conditionString.append(" " + field); } + if(backwardCompatibility) + newFields.add("facts." + field); } + if(backwardCompatibility) { + fields.clear(); + fields.addAll(newFields); + } } actions.addAll(getConditionKeys(conditionString.toString())); diff --git a/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/filesource/AssetsFileSource.java b/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/filesource/AssetsFileSource.java index 6b6da5b20..3d5a6774e 100644 --- a/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/filesource/AssetsFileSource.java +++ b/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/filesource/AssetsFileSource.java @@ -4,17 +4,21 @@ import com.vijay.jsonwizard.constants.JsonFormConstants; import com.vijay.jsonwizard.interfaces.FormFileSource; +import com.vijay.jsonwizard.rules.YamlRuleDefinitionReaderExt; +import com.vijay.jsonwizard.utils.NativeFormsProperties; import com.vijay.jsonwizard.utils.Utils; import org.jeasy.rules.api.Rules; import org.jeasy.rules.mvel.MVELRuleFactory; -import org.jeasy.rules.support.YamlRuleDefinitionReader; +import org.jeasy.rules.support.reader.YamlRuleDefinitionReader; import org.json.JSONObject; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; +import timber.log.Timber; + /*** * used to read files stored on the APP's asset folder * @@ -25,7 +29,16 @@ public class AssetsFileSource implements FormFileSource { private MVELRuleFactory mvelRuleFactory; private AssetsFileSource() { - this.mvelRuleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader()); + if(Utils.enabledProperty(NativeFormsProperties.KEY.EASY_RULES_V3_COMPATIBILITY)) + { + this.mvelRuleFactory = new MVELRuleFactory(new YamlRuleDefinitionReaderExt()); + Timber.e("AssetsFileSource Engaged"); + } + else + { + this.mvelRuleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader()); + Timber.e("AssetsFileSource not Engaged"); + } } @Override diff --git a/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/filesource/DiskFileSource.java b/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/filesource/DiskFileSource.java index a165a2e53..a352eb1bf 100644 --- a/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/filesource/DiskFileSource.java +++ b/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/filesource/DiskFileSource.java @@ -6,11 +6,13 @@ import com.vijay.jsonwizard.constants.JsonFormConstants; import com.vijay.jsonwizard.interfaces.FormFileSource; +import com.vijay.jsonwizard.rules.YamlRuleDefinitionReaderExt; +import com.vijay.jsonwizard.utils.NativeFormsProperties; import com.vijay.jsonwizard.utils.Utils; import org.jeasy.rules.api.Rules; import org.jeasy.rules.mvel.MVELRuleFactory; -import org.jeasy.rules.support.YamlRuleDefinitionReader; +import org.jeasy.rules.support.reader.YamlRuleDefinitionReader; import org.json.JSONObject; import java.io.BufferedReader; @@ -20,6 +22,9 @@ import java.io.InputStream; import java.io.InputStreamReader; +import timber.log.Timber; + + /** * Returns forms rules and other files stored on the devices * hard disk @@ -30,7 +35,15 @@ public class DiskFileSource implements FormFileSource { private MVELRuleFactory mvelRuleFactory; private DiskFileSource() { - this.mvelRuleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader()); + if(Utils.enabledProperty(NativeFormsProperties.KEY.EASY_RULES_V3_COMPATIBILITY)){ + this.mvelRuleFactory = new MVELRuleFactory(new YamlRuleDefinitionReaderExt()); + Timber.e("Disk File source Mvel backward compat engaged"); + + } + else { + this.mvelRuleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader()); + Timber.e("Disk File source Mvel backward compat not engaged"); + } } @Override diff --git a/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/rules/RulesEngineFactory.java b/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/rules/RulesEngineFactory.java index 85a840ddb..32bb112ab 100644 --- a/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/rules/RulesEngineFactory.java +++ b/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/rules/RulesEngineFactory.java @@ -1,12 +1,14 @@ package com.vijay.jsonwizard.rules; import android.content.Context; + import androidx.annotation.NonNull; import com.google.gson.Gson; import com.vijay.jsonwizard.activities.JsonFormBaseActivity; import com.vijay.jsonwizard.constants.JsonFormConstants; import com.vijay.jsonwizard.factory.FileSourceFactoryHelper; +import com.vijay.jsonwizard.utils.NativeFormsProperties; import com.vijay.jsonwizard.utils.Utils; import org.jeasy.rules.api.Facts; @@ -14,11 +16,11 @@ import org.jeasy.rules.api.RuleListener; import org.jeasy.rules.api.Rules; import org.jeasy.rules.api.RulesEngine; +import org.jeasy.rules.api.RulesEngineParameters; import org.jeasy.rules.core.DefaultRulesEngine; -import org.jeasy.rules.core.RulesEngineParameters; import org.jeasy.rules.mvel.MVELRule; import org.jeasy.rules.mvel.MVELRuleFactory; -import org.jeasy.rules.support.YamlRuleDefinitionReader; +import org.jeasy.rules.support.reader.YamlRuleDefinitionReader; import org.json.JSONArray; import org.json.JSONObject; import org.smartregister.client.utils.contract.ClientFormContract; @@ -43,16 +45,25 @@ public class RulesEngineFactory implements RuleListener { private RulesEngineHelper rulesEngineHelper; private Facts globalFacts; private MVELRuleFactory mvelRuleFactory; - + private boolean backwardCompatibility = false; public RulesEngineFactory(Context context, Map globalValues) { this.context = context; + backwardCompatibility = Utils.getProperties(context).getPropertyBoolean(NativeFormsProperties.KEY.EASY_RULES_V3_COMPATIBILITY); RulesEngineParameters parameters = new RulesEngineParameters().skipOnFirstAppliedRule(true); this.defaultRulesEngine = new DefaultRulesEngine(parameters); ((DefaultRulesEngine) this.defaultRulesEngine).registerRuleListener(this); this.ruleMap = new HashMap<>(); gson = new Gson(); this.rulesEngineHelper = new RulesEngineHelper(); - this.mvelRuleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader()); + if(backwardCompatibility) { + this.mvelRuleFactory = new MVELRuleFactory(new YamlRuleDefinitionReaderExt()); + Timber.e("yaml ext Reader engaged : RulesEngineFactory"); + } + else + { + this.mvelRuleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader()); + Timber.e("yaml ext Reader disengaged : RulesEngineFactory"); + } if (globalValues != null) { @@ -64,6 +75,7 @@ public RulesEngineFactory(Context context, Map globalValues) { } public RulesEngineFactory() { + } private Rules getDynamicRulesFromJsonArray(@NonNull JSONArray jsonArray, @NonNull String type) { @@ -99,7 +111,7 @@ private MVELRule getDynamicRulesFromJsonObject(@NonNull JSONObject jsonObjectDyn dynamicMvelRule.setDescription(jsonObjectDynamicRule.optString(RuleConstant.DESCRIPTION)); dynamicMvelRule.setPriority(jsonObjectDynamicRule.optInt(RuleConstant.PRIORITY)); dynamicMvelRule.when(jsonObjectDynamicRule.optString(RuleConstant.CONDITION)); - dynamicMvelRule.then(jsonObjectDynamicRule.optString(RuleConstant.ACTIONS)); + dynamicMvelRule.then("facts." + jsonObjectDynamicRule.optString(RuleConstant.ACTIONS)); dynamicMvelRule.name(jsonObjectDynamicRule.optString(RuleConstant.NAME)); return dynamicMvelRule; } catch (Exception e) { @@ -249,6 +261,14 @@ public String getConstraint(Facts constraintFact, String ruleFilename) { @Override public boolean beforeEvaluate(Rule rule, Facts facts) { + + HashMap myMap = new HashMap<>(); + Map iterationFacts = facts.asMap(); + for (String key : iterationFacts.keySet()) { + myMap.put(key, iterationFacts.get(key)); + } + + facts.put("facts", myMap); return selectedRuleName != null && selectedRuleName.equals(rule.getName()); } @@ -257,19 +277,38 @@ public void afterEvaluate(Rule rule, Facts facts, boolean evaluationResult) { //Overriden } + @Override public void beforeExecute(Rule rule, Facts facts) { - //Overriden + if(backwardCompatibility) { + Timber.e("Putting facts in beforeExecute"); + HashMap myMap = new HashMap<>(); + facts.put("facts", myMap); + } + } @Override public void onSuccess(Rule rule, Facts facts) { - //Overriden + if(backwardCompatibility) { + Timber.e("Putting facts in onSuccess"); + HashMap myMap = facts.get("facts"); + + for (String key : + myMap.keySet()) { + facts.put(key, myMap.get(key)); + } + + facts.remove("facts"); + } } @Override public void onFailure(Rule rule, Facts facts, Exception exception) { - //Overriden + + Timber.e("Putting facts in onFailure"); + facts.remove("facts"); + } public String getRulesFolderPath() { diff --git a/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/rules/YamlRuleDefinitionReaderExt.java b/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/rules/YamlRuleDefinitionReaderExt.java new file mode 100644 index 000000000..620c89857 --- /dev/null +++ b/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/rules/YamlRuleDefinitionReaderExt.java @@ -0,0 +1,32 @@ +package com.vijay.jsonwizard.rules; + +import org.jeasy.rules.support.RuleDefinition; +import org.jeasy.rules.support.reader.YamlRuleDefinitionReader; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Created by Ephraim Kigamba - nek.eam@gmail.com on 22-11-2022. + */ +public class YamlRuleDefinitionReaderExt extends YamlRuleDefinitionReader { + + + @Override + protected RuleDefinition createRuleDefinition(Map map) { + RuleDefinition ruleDefinition = super.createRuleDefinition(map); + + List actionList = ruleDefinition.getActions(); + List newActionList = new ArrayList<>(); + + for (int i = 0; i < actionList.size(); i++) { + newActionList.add("facts." + actionList.get(i)); + } + + actionList.clear(); + actionList.addAll(newActionList); + + return ruleDefinition; + } +} diff --git a/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/utils/NativeFormsProperties.java b/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/utils/NativeFormsProperties.java index c31994cba..872b01488 100644 --- a/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/utils/NativeFormsProperties.java +++ b/android-json-form-wizard/src/main/java/com/vijay/jsonwizard/utils/NativeFormsProperties.java @@ -23,6 +23,7 @@ public final static class KEY { //Widgets public static final String WIDGET_DATEPICKER_IS_NUMERIC = "widget.datepicker.is.numeric"; public static final String WIDGET_VALUE_TRANSLATED = "widget.value.translated"; + public static final String EASY_RULES_V3_COMPATIBILITY = "easy_rule.v3.compatibility"; } diff --git a/android-json-form-wizard/src/test/java/com/vijay/jsonwizard/rules/RulesEngineFactoryTest.java b/android-json-form-wizard/src/test/java/com/vijay/jsonwizard/rules/RulesEngineFactoryTest.java index 8032f9306..dee8f9921 100644 --- a/android-json-form-wizard/src/test/java/com/vijay/jsonwizard/rules/RulesEngineFactoryTest.java +++ b/android-json-form-wizard/src/test/java/com/vijay/jsonwizard/rules/RulesEngineFactoryTest.java @@ -6,6 +6,9 @@ import com.vijay.jsonwizard.activities.JsonFormActivity; import com.vijay.jsonwizard.constants.JsonFormConstants; +import com.vijay.jsonwizard.utils.NativeFormsProperties; +import com.vijay.jsonwizard.utils.Utils; + import org.jeasy.rules.api.Facts; import org.jeasy.rules.api.Rule; import org.jeasy.rules.api.Rules; @@ -43,9 +46,13 @@ public class RulesEngineFactoryTest { @Mock private AssetManager assetManager; + private NativeFormsProperties nativeFormsProperties; + @Before public void setUp() { MockitoAnnotations.initMocks(this); + nativeFormsProperties = Utils.getProperties(context); + nativeFormsProperties.setProperty(NativeFormsProperties.KEY.EASY_RULES_V3_COMPATIBILITY,"true"); rulesEngineFactory = new RulesEngineFactory(); } diff --git a/form_tester/src/main/assets/app.properties b/form_tester/src/main/assets/app.properties index a2e8a9e3a..b9ebaae30 100644 --- a/form_tester/src/main/assets/app.properties +++ b/form_tester/src/main/assets/app.properties @@ -1,2 +1,3 @@ widget.datepicker.is.numeric=true -widget.value.translated=true \ No newline at end of file +widget.value.translated=true +easy_rule.v3.compatibility=true \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 5abb92c86..c613ca76a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -VERSION_NAME=3.1.1-SNAPSHOT +VERSION_NAME=3.1.5-LOCAL-SNAPSHOT VERSION_CODE=1 GROUP=org.smartregister POM_SETTING_DESCRIPTION=OpenSRP Client Native Form Json Wizard