This is an automated email from the ASF dual-hosted git repository.

dgriffon pushed a commit to branch UNOMI-518-fix-trackedConditions
in repository https://gitbox.apache.org/repos/asf/unomi.git

commit a29af149b91c206f9dc2517991f5eaf772f0354a
Author: David Griffon <[email protected]>
AuthorDate: Thu Oct 21 13:17:46 2021 +0200

    UNOMI-518 : allow to use custom parameters in rules with tracked conditions
---
 .../test/java/org/apache/unomi/itests/BaseIT.java  |  2 +
 .../org/apache/unomi/itests/RuleServiceIT.java     | 41 ++++++++++++++
 .../test/resources/testClickEventCondition.json    | 58 +++++++++++++++++++
 .../services/impl/rules/RulesServiceImpl.java      | 65 +++++++++++++++-------
 4 files changed, 146 insertions(+), 20 deletions(-)

diff --git a/itests/src/test/java/org/apache/unomi/itests/BaseIT.java 
b/itests/src/test/java/org/apache/unomi/itests/BaseIT.java
index 9f8a2d9..81d28da 100644
--- a/itests/src/test/java/org/apache/unomi/itests/BaseIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/BaseIT.java
@@ -158,6 +158,8 @@ public abstract class BaseIT {
                         
"src/test/resources/testCopyPropertiesWithoutSystemTags.json")),
                 
replaceConfigurationFile("data/tmp/testLoginEventCondition.json", new File(
                         "src/test/resources/testLoginEventCondition.json")),
+                
replaceConfigurationFile("data/tmp/testClickEventCondition.json", new File(
+                        "src/test/resources/testClickEventCondition.json")),
                 replaceConfigurationFile("data/tmp/testRuleGroovyAction.json", 
new File(
                         "src/test/resources/testRuleGroovyAction.json")),
                 
replaceConfigurationFile("data/tmp/groovy/UpdateAddressAction.groovy", new File(
diff --git a/itests/src/test/java/org/apache/unomi/itests/RuleServiceIT.java 
b/itests/src/test/java/org/apache/unomi/itests/RuleServiceIT.java
index 7a4488b..e94e88a 100644
--- a/itests/src/test/java/org/apache/unomi/itests/RuleServiceIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/RuleServiceIT.java
@@ -17,9 +17,13 @@
 package org.apache.unomi.itests;
 
 import org.apache.unomi.api.*;
+import org.apache.unomi.api.conditions.Condition;
+import org.apache.unomi.api.conditions.ConditionType;
 import org.apache.unomi.api.rules.Rule;
 import org.apache.unomi.api.services.EventService;
 import org.apache.unomi.api.services.RulesService;
+import org.apache.unomi.persistence.spi.CustomObjectMapper;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -32,7 +36,9 @@ import org.slf4j.LoggerFactory;
 
 import javax.inject.Inject;
 
+import java.io.File;
 import java.io.IOException;
+import java.net.MalformedURLException;
 import java.util.*;
 
 import static org.junit.Assert.*;
@@ -176,6 +182,41 @@ public class RuleServiceIT extends BaseIT {
         return new Event(UUID.randomUUID().toString(), "view", session, 
profile, TEST_SCOPE, sourceItem, targetItem, new Date());
     }
 
+    @Test
+    public void testGetTrackedConditions() throws InterruptedException, 
IOException {
+        // Add custom condition with parameter
+        ConditionType conditionType = 
CustomObjectMapper.getObjectMapper().readValue(
+                new 
File("data/tmp/testClickEventCondition.json").toURI().toURL(), 
ConditionType.class);
+        definitionsService.setConditionType(conditionType);
+        refreshPersistence();
+        rulesService.refreshRules();
+        // Test tracked parameter
+        // Add rule that has a trackParameter condition that matches
+        ConditionBuilder builder = new ConditionBuilder(definitionsService);
+        Rule trackParameterRule = new Rule(new Metadata(TEST_SCOPE, 
"tracked-parameter-rule", "Tracked parameter rule", "A rule with tracked 
parameter"));
+        Condition trackedCondition = 
builder.condition("clickEventCondition").build();
+        trackedCondition.setParameter("tracked.properties.pageInfo.pagePath", 
"/test-page.html");
+        
trackedCondition.getConditionType().getMetadata().getSystemTags().add("trackedCondition");
+        trackParameterRule.setCondition(trackedCondition);
+        rulesService.setRule(trackParameterRule);
+        // Add rule that has a trackParameter condition that does not match
+        Rule unTrackParameterRule = new Rule(new Metadata(TEST_SCOPE, 
"not-tracked-parameter-rule", "Not Tracked parameter rule", "A rule that has a 
parameter not tracked"));
+        Condition unTrackedCondition = 
builder.condition("clickEventCondition").build();
+        
unTrackedCondition.setParameter("tracked.properties.pageInfo.pagePath", 
"/test-page-that-does-not-exist.html");
+        
unTrackedCondition.getConditionType().getMetadata().getSystemTags().add("trackedCondition");
+        unTrackParameterRule.setCondition(unTrackedCondition);
+        rulesService.setRule(unTrackParameterRule);
+        refreshPersistence();
+        rulesService.refreshRules();
+        // Check that the given event return the tracked condition
+        Profile profile = new Profile(UUID.randomUUID().toString());
+        Session session = new Session(UUID.randomUUID().toString(), profile, 
new Date(), TEST_SCOPE);
+        Event viewEvent = generateViewEvent(session, profile);
+        Set<Condition> trackedConditions = 
rulesService.getTrackedConditions(viewEvent.getTarget());
+        Assert.assertTrue(trackedConditions.contains(trackedCondition));
+        Assert.assertFalse(trackedConditions.contains(unTrackedCondition));
+    }
+
     @Override
     public void updateServices() throws InterruptedException {
         super.updateServices();
diff --git a/itests/src/test/resources/testClickEventCondition.json 
b/itests/src/test/resources/testClickEventCondition.json
new file mode 100644
index 0000000..d99e4b7
--- /dev/null
+++ b/itests/src/test/resources/testClickEventCondition.json
@@ -0,0 +1,58 @@
+{
+  "metadata": {
+    "id": "clickEventCondition",
+    "name": "clickEventCondition",
+    "description": "",
+    "systemTags": [
+      "availableToEndUser",
+      "behavioral",
+      "profileTags",
+      "event",
+      "condition",
+      "eventCondition",
+      "usableInPastEventCondition",
+      "trackedCondition"
+    ],
+    "readOnly": true
+  },
+  "parentCondition": {
+    "type": "booleanCondition",
+    "parameterValues": {
+      "subConditions": [
+        {
+          "type": "eventTypeCondition",
+          "parameterValues": {
+            "eventTypeId": "click"
+          }
+        },
+        {
+          "type": "sourceEventPropertyCondition",
+          "parameterValues": {
+            "path": "parameter::tracked.properties.pageInfo.pagePath"
+          }
+        },
+        {
+          "type": "eventPropertyCondition",
+          "parameterValues": {
+            "propertyName": "target.itemId",
+            "propertyValue": "parameter::itemId",
+            "comparisonOperator": "equals"
+          }
+        }
+      ],
+      "operator": "and"
+    }
+  },
+  "parameters": [
+    {
+      "id": "tracked.properties.pageInfo.pagePath",
+      "type": "string",
+      "multivalued": false
+    },
+    {
+      "id": "itemId",
+      "type": "string",
+      "multivalued": false
+    }
+  ]
+}
\ No newline at end of file
diff --git 
a/services/src/main/java/org/apache/unomi/services/impl/rules/RulesServiceImpl.java
 
b/services/src/main/java/org/apache/unomi/services/impl/rules/RulesServiceImpl.java
index 01ae985..8cf3a1f 100644
--- 
a/services/src/main/java/org/apache/unomi/services/impl/rules/RulesServiceImpl.java
+++ 
b/services/src/main/java/org/apache/unomi/services/impl/rules/RulesServiceImpl.java
@@ -17,6 +17,7 @@
 
 package org.apache.unomi.services.impl.rules;
 
+import org.apache.commons.lang3.StringUtils;
 import org.apache.unomi.api.Event;
 import org.apache.unomi.api.Item;
 import org.apache.unomi.api.Metadata;
@@ -45,6 +46,7 @@ import java.util.concurrent.TimeUnit;
 public class RulesServiceImpl implements RulesService, EventListenerService, 
SynchronousBundleListener {
 
     public static final String RULE_QUERY_PREFIX = "rule_";
+    public static final String TRACKED_PARAMETER_PREFIX = "tracked.";
     private static final Logger logger = 
LoggerFactory.getLogger(RulesServiceImpl.class.getName());
 
     private BundleContext bundleContext;
@@ -57,14 +59,14 @@ public class RulesServiceImpl implements RulesService, 
EventListenerService, Syn
     private ActionExecutorDispatcher actionExecutorDispatcher;
     private List<Rule> allRules;
 
-    private Map<String,RuleStatistics> allRuleStatistics = new 
ConcurrentHashMap<>();
+    private Map<String, RuleStatistics> allRuleStatistics = new 
ConcurrentHashMap<>();
 
     private Integer rulesRefreshInterval = 1000;
     private Integer rulesStatisticsRefreshInterval = 10000;
 
     private List<RuleListenerService> ruleListeners = new 
CopyOnWriteArrayList<RuleListenerService>();
 
-    private Map<String,Set<Rule>> rulesByEventType = new HashMap<>();
+    private Map<String, Set<Rule>> rulesByEventType = new HashMap<>();
     private Boolean optimizedRulesActivated = true;
 
     public void setBundleContext(BundleContext bundleContext) {
@@ -282,8 +284,8 @@ public class RulesServiceImpl implements RulesService, 
EventListenerService, Syn
         return rules;
     }
 
-    private Map<String,Set<Rule>> getRulesByEventType(List<Rule> rules) {
-        Map<String,Set<Rule>> newRulesByEventType = new HashMap<>();
+    private Map<String, Set<Rule>> getRulesByEventType(List<Rule> rules) {
+        Map<String, Set<Rule>> newRulesByEventType = new HashMap<>();
         for (Rule rule : rules) {
             updateRulesByEventType(newRulesByEventType, rule);
         }
@@ -313,7 +315,7 @@ public class RulesServiceImpl implements RulesService, 
EventListenerService, Syn
             changes |= eventService.send(ruleFired);
 
             RuleStatistics ruleStatistics = getLocalRuleStatistics(rule);
-            
ruleStatistics.setLocalExecutionCount(ruleStatistics.getLocalExecutionCount()+1);
+            
ruleStatistics.setLocalExecutionCount(ruleStatistics.getLocalExecutionCount() + 
1);
             
ruleStatistics.setLocalActionsTime(ruleStatistics.getLocalActionsTime() + 
totalActionsTime);
             this.allRuleStatistics.put(rule.getItemId(), ruleStatistics);
         }
@@ -328,14 +330,14 @@ public class RulesServiceImpl implements RulesService, 
EventListenerService, Syn
         return persistenceService.load(ruleId, RuleStatistics.class);
     }
 
-    public Map<String,RuleStatistics> getAllRuleStatistics() {
+    public Map<String, RuleStatistics> getAllRuleStatistics() {
         return allRuleStatistics;
     }
 
     @Override
     public void resetAllRuleStatistics() {
         Condition matchAllCondition = new 
Condition(definitionsService.getConditionType("matchAllCondition"));
-        
persistenceService.removeByQuery(matchAllCondition,RuleStatistics.class);
+        persistenceService.removeByQuery(matchAllCondition, 
RuleStatistics.class);
         allRuleStatistics.clear();
     }
 
@@ -348,7 +350,7 @@ public class RulesServiceImpl implements RulesService, 
EventListenerService, Syn
     }
 
     public PartialList<Metadata> getRuleMetadatas(Query query) {
-        if(query.isForceRefresh()){
+        if (query.isForceRefresh()) {
             persistenceService.refresh();
         }
         definitionsService.resolveConditionType(query.getCondition());
@@ -394,24 +396,47 @@ public class RulesServiceImpl implements RulesService, 
EventListenerService, Syn
         persistenceService.save(rule);
     }
 
-    public Set<Condition> getTrackedConditions(Item source){
+    public Set<Condition> getTrackedConditions(Item source) {
         Set<Condition> trackedConditions = new HashSet<>();
         for (Rule r : allRules) {
             if (!r.getMetadata().isEnabled()) {
                 continue;
             }
-            Condition trackedCondition = 
definitionsService.extractConditionBySystemTag(r.getCondition(), 
"trackedCondition");
-            if(trackedCondition != null){
-                Condition sourceEventPropertyCondition = 
definitionsService.extractConditionBySystemTag(r.getCondition(), 
"sourceEventCondition");
-                if(source != null && sourceEventPropertyCondition != null) {
-                    ParserHelper.resolveConditionType(definitionsService, 
sourceEventPropertyCondition, "rule " + r.getItemId() + " source event 
condition");
-                    
if(persistenceService.testMatch(sourceEventPropertyCondition, source)){
+            Condition ruleCondition = r.getCondition();
+            Condition trackedCondition = 
definitionsService.extractConditionBySystemTag(ruleCondition, 
"trackedCondition");
+            if (trackedCondition != null) {
+                Condition evalCondition = 
definitionsService.extractConditionBySystemTag(ruleCondition, 
"sourceEventCondition");
+                if (evalCondition != null) {
+                    if (persistenceService.testMatch(evalCondition, source)) {
                         trackedConditions.add(trackedCondition);
                     }
                 } else {
-                    trackedConditions.add(trackedCondition);
+                    // lookup for track parameters
+                    Map<String, Object> trackedParameters = new HashMap<>();
+                    trackedCondition.getParameterValues().forEach((key, value) 
-> {
+                        if (!TRACKED_PARAMETER_PREFIX.equals(key) && 
StringUtils.startsWith(key, TRACKED_PARAMETER_PREFIX)) {
+                            
trackedParameters.put(StringUtils.substringAfter(key, 
TRACKED_PARAMETER_PREFIX), value);
+                        }
+                    });
+                    if (trackedParameters.size() > 0) {
+                        evalCondition = new 
Condition(definitionsService.getConditionType("booleanCondition"));
+                        evalCondition.setParameter("operator", "and");
+                        ArrayList<Condition> conditions = new ArrayList<>();
+                        trackedParameters.forEach((key, value) -> {
+                            Condition propCondition = new 
Condition(definitionsService.getConditionType("eventPropertyCondition"));
+                            propCondition.setParameter("comparisonOperator", 
"equals");
+                            propCondition.setParameter("propertyName", key);
+                            propCondition.setParameter("propertyValue", value);
+                            conditions.add(propCondition);
+                        });
+                        evalCondition.setParameter("subConditions", 
conditions);
+                        if (persistenceService.testMatch(evalCondition, 
source)) {
+                            trackedConditions.add(trackedCondition);
+                        }
+                    } else {
+                        trackedConditions.add(trackedCondition);
+                    }
                 }
-
             }
         }
         return trackedConditions;
@@ -428,7 +453,7 @@ public class RulesServiceImpl implements RulesService, 
EventListenerService, Syn
                 refreshRules();
             }
         };
-        
schedulerService.getScheduleExecutorService().scheduleWithFixedDelay(task, 
0,rulesRefreshInterval, TimeUnit.MILLISECONDS);
+        
schedulerService.getScheduleExecutorService().scheduleWithFixedDelay(task, 0, 
rulesRefreshInterval, TimeUnit.MILLISECONDS);
 
         TimerTask statisticsTask = new TimerTask() {
             @Override
@@ -456,7 +481,7 @@ public class RulesServiceImpl implements RulesService, 
EventListenerService, Syn
 
     private void syncRuleStatistics() {
         List<RuleStatistics> allPersistedRuleStatisticsList = 
persistenceService.getAllItems(RuleStatistics.class);
-        Map<String,RuleStatistics> allPersistedRuleStatistics = new 
HashMap<>();
+        Map<String, RuleStatistics> allPersistedRuleStatistics = new 
HashMap<>();
         for (RuleStatistics ruleStatistics : allPersistedRuleStatisticsList) {
             allPersistedRuleStatistics.put(ruleStatistics.getItemId(), 
ruleStatistics);
         }
@@ -543,7 +568,7 @@ public class RulesServiceImpl implements RulesService, 
EventListenerService, Syn
         }
     }
 
-    private void updateRulesByEventType(Map<String,Set<Rule>> 
rulesByEventType, Rule rule) {
+    private void updateRulesByEventType(Map<String, Set<Rule>> 
rulesByEventType, Rule rule) {
         Set<String> eventTypeIds = 
ParserHelper.resolveConditionEventTypes(rule.getCondition());
         for (String eventTypeId : eventTypeIds) {
             Set<Rule> rules = rulesByEventType.get(eventTypeId);

Reply via email to