UNOMI-411 Bug fix in profile property condition and add getNestedProperty method (#229)
* add nested property and fix bug in property condition evaluator for exists operator
* Support direct property from getNestedProperty
* Add itest
diff --git a/api/pom.xml b/api/pom.xml
index 5394ff1..0bc24e4 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -37,7 +37,10 @@
<version>2.2.11</version>
<scope>provided</scope>
</dependency>
-
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ </dependency>
</dependencies>
<reporting>
diff --git a/api/src/main/java/org/apache/unomi/api/Event.java b/api/src/main/java/org/apache/unomi/api/Event.java
index e7ff5a6..6b4e1e8 100644
--- a/api/src/main/java/org/apache/unomi/api/Event.java
+++ b/api/src/main/java/org/apache/unomi/api/Event.java
@@ -17,6 +17,7 @@
package org.apache.unomi.api;
+import org.apache.commons.lang3.StringUtils;
import org.apache.unomi.api.actions.ActionPostExecutor;
import javax.xml.bind.annotation.XmlTransient;
@@ -324,6 +325,30 @@
}
/**
+ * Retrieves the value of the nested property identified by the specified name.
+ *
+ * @param name the name of the property to be retrieved, splited in the nested properties with "."
+ * @return the value of the property identified by the specified name
+ */
+ public Object getNestedProperty(String name) {
+ if (!name.contains(".")) {
+ return getProperty(name);
+ }
+
+ Map properties = this.properties;
+ String[] propertyPath = StringUtils.substringBeforeLast(name, ".").split("\\.");
+ String propertyName = StringUtils.substringAfterLast(name, ".");
+
+ for (String property: propertyPath) {
+ properties = (Map) properties.get(property);
+ if (properties == null) {
+ return null;
+ }
+ }
+ return properties.get(propertyName);
+ }
+
+ /**
* Retrieves the properties.
*
* @return the properties
diff --git a/api/src/main/java/org/apache/unomi/api/Profile.java b/api/src/main/java/org/apache/unomi/api/Profile.java
index ba75da9..7115bd5 100644
--- a/api/src/main/java/org/apache/unomi/api/Profile.java
+++ b/api/src/main/java/org/apache/unomi/api/Profile.java
@@ -17,6 +17,7 @@
package org.apache.unomi.api;
+import org.apache.commons.lang3.StringUtils;
import org.apache.unomi.api.segments.Scoring;
import org.apache.unomi.api.segments.Segment;
@@ -95,6 +96,30 @@
}
/**
+ * Retrieves the value of the nested property identified by the specified name.
+ *
+ * @param name the name of the property to be retrieved, splited in the nested properties with "."
+ * @return the value of the property identified by the specified name
+ */
+ public Object getNestedProperty(String name) {
+ if (!name.contains(".")) {
+ return getProperty(name);
+ }
+
+ Map properties = this.properties;
+ String[] propertyPath = StringUtils.substringBeforeLast(name, ".").split("\\.");
+ String propertyName = StringUtils.substringAfterLast(name, ".");
+
+ for (String property: propertyPath) {
+ properties = (Map) properties.get(property);
+ if (properties == null) {
+ return null;
+ }
+ }
+ return properties.get(propertyName);
+ }
+
+ /**
* Retrieves a Map of all property name - value pairs for this profile.
*
* @return a Map of all property name - value pairs for this profile
diff --git a/itests/src/test/java/org/apache/unomi/itests/EventServiceIT.java b/itests/src/test/java/org/apache/unomi/itests/EventServiceIT.java
index 530baa8..9f3eb05 100644
--- a/itests/src/test/java/org/apache/unomi/itests/EventServiceIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/EventServiceIT.java
@@ -38,6 +38,8 @@
import javax.inject.Inject;
import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
import java.text.SimpleDateFormat;
import java.text.ParseException;
@@ -46,6 +48,7 @@
import org.junit.Assert;
+
/**
* An integration test for the event service
*/
@@ -150,4 +153,20 @@
Assert.assertEquals(0, profiles.getList().size());
}
+ @Test
+ public void test_EventGetNestedProperty() {
+ String nestedProperty = "outerProperty.innerProperty";
+ String testValue = "test-value";
+ String eventId = "test-event-id-" + System.currentTimeMillis();
+ String profileId = "test-profile-id";
+ String eventType = "test-type";
+ Profile profile = new Profile(profileId);
+ Event event = new Event(eventId, eventType, null, profile, null, null, null, new Date());
+ final Map<String, String> innerProperty = new HashMap<>();
+ innerProperty.put("innerProperty", testValue);
+ event.setProperty("outerProperty", innerProperty);
+ String value = (String) event.getNestedProperty(nestedProperty);
+ Assert.assertEquals(testValue, value);
+ }
+
}
diff --git a/itests/src/test/java/org/apache/unomi/itests/ProfileServiceIT.java b/itests/src/test/java/org/apache/unomi/itests/ProfileServiceIT.java
index 2d0ad9a..25788bd 100644
--- a/itests/src/test/java/org/apache/unomi/itests/ProfileServiceIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/ProfileServiceIT.java
@@ -37,6 +37,9 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.HashMap;
+import java.util.Map;
+
import javax.inject.Inject;
/**
@@ -136,5 +139,18 @@
}
}
+ @Test
+ public void test_EventGetNestedProperty() {
+ String nestedProperty = "outerProperty.innerProperty";
+ String testValue = "test-value";
+ String profileId = "test-profile-id";
+ Profile profile = new Profile(profileId);
+ final Map<String, String> innerProperty = new HashMap<>();
+ innerProperty.put("innerProperty", testValue);
+ profile.setProperty("outerProperty", innerProperty);
+ String value = (String) profile.getNestedProperty(nestedProperty);
+ assertEquals(testValue, value);
+ }
+
}
diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionEvaluator.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionEvaluator.java
index 13319b6..6514f04 100644
--- a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionEvaluator.java
+++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionEvaluator.java
@@ -199,6 +199,9 @@
} else if (actualValue == null) {
return op.equals("missing");
} else if (op.equals("exists")) {
+ if (actualValue instanceof List) {
+ return ((List) actualValue).size() > 0;
+ }
return true;
} else if (op.equals("equals")) {
if (actualValue instanceof Collection) {