You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@unomi.apache.org by dr...@apache.org on 2016/08/26 09:42:05 UTC

incubator-unomi git commit: UNOMI-32 : Improved profile updates to only merge specified properties. Send event only if profile is modifed. Also merge proeprty types on save.

Repository: incubator-unomi
Updated Branches:
  refs/heads/master b2cb9ee0d -> ec58db2c9


UNOMI-32 : Improved profile updates to only merge specified properties. Send event only if profile is modifed.  Also merge proeprty types on save.


Project: http://git-wip-us.apache.org/repos/asf/incubator-unomi/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-unomi/commit/ec58db2c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-unomi/tree/ec58db2c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-unomi/diff/ec58db2c

Branch: refs/heads/master
Commit: ec58db2c9edc75ea5d5acbf2d0bc902a724748bc
Parents: b2cb9ee
Author: Thomas Draier <dr...@apache.org>
Authored: Fri Aug 26 11:41:54 2016 +0200
Committer: Thomas Draier <dr...@apache.org>
Committed: Fri Aug 26 11:41:54 2016 +0200

----------------------------------------------------------------------
 .../java/org/apache/unomi/api/PropertyType.java | 16 ++--
 .../unomi/api/services/ProfileService.java      |  8 ++
 .../unomi/rest/ProfileServiceEndPoint.java      | 12 +--
 .../services/services/ProfileServiceImpl.java   | 77 ++++++++++++++++++--
 4 files changed, 94 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/ec58db2c/api/src/main/java/org/apache/unomi/api/PropertyType.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/unomi/api/PropertyType.java b/api/src/main/java/org/apache/unomi/api/PropertyType.java
index ab58990..4d5bf6f 100644
--- a/api/src/main/java/org/apache/unomi/api/PropertyType.java
+++ b/api/src/main/java/org/apache/unomi/api/PropertyType.java
@@ -44,12 +44,12 @@ public class PropertyType extends MetadataItem {
     private List<NumericRange> numericRanges = new ArrayList<>();
     private List<IpRange> ipRanges = new ArrayList<>();
     private Set<String> automaticMappingsFrom = new HashSet<>();
-    private double rank;
+    private Double rank;
     private String mergeStrategy;
     private Set<Tag> tags = new TreeSet<Tag>();
     private Set<String> tagIds = new LinkedHashSet<String>();
-    private boolean multivalued;
-    private boolean protekted = false;
+    private Boolean multivalued;
+    private Boolean protekted;
 
     /**
      * Instantiates a new Property type.
@@ -210,7 +210,7 @@ public class PropertyType extends MetadataItem {
      *
      * @return the rank of this PropertyType for ordering purpose
      */
-    public double getRank() {
+    public Double getRank() {
         return rank;
     }
 
@@ -219,7 +219,7 @@ public class PropertyType extends MetadataItem {
      *
      * @param rank the rank of this PropertyType for ordering purpose
      */
-    public void setRank(double rank) {
+    public void setRank(Double rank) {
         this.rank = rank;
     }
 
@@ -300,7 +300,7 @@ public class PropertyType extends MetadataItem {
      *
      * @return {@code true} if properties of this type should be multi-valued, {@code false} otherwise
      */
-    public boolean isMultivalued() {
+    public Boolean isMultivalued() {
         return multivalued;
     }
 
@@ -309,7 +309,7 @@ public class PropertyType extends MetadataItem {
      *
      * @param multivalued {@code true} if properties of this type should be multi-valued, {@code false} otherwise
      */
-    public void setMultivalued(boolean multivalued) {
+    public void setMultivalued(Boolean multivalued) {
         this.multivalued = multivalued;
     }
 
@@ -320,7 +320,7 @@ public class PropertyType extends MetadataItem {
      *
      * @return {@code true} if properties of this type are protected, {@code false} otherwise
      */
-    public boolean isProtected() {
+    public Boolean isProtected() {
         return protekted;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/ec58db2c/api/src/main/java/org/apache/unomi/api/services/ProfileService.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/unomi/api/services/ProfileService.java b/api/src/main/java/org/apache/unomi/api/services/ProfileService.java
index c13036a..a998e5e 100644
--- a/api/src/main/java/org/apache/unomi/api/services/ProfileService.java
+++ b/api/src/main/java/org/apache/unomi/api/services/ProfileService.java
@@ -106,6 +106,14 @@ public interface ProfileService {
     Profile save(Profile profile);
 
     /**
+     * Merge the specified profile properties in an existing profile,or save new profile if it does not exist yet
+     *
+     * @param profile the profile to be saved
+     * @return the newly saved profile
+     */
+    boolean saveOrmerge(Profile profile);
+
+    /**
      * Removes the profile (or persona if the {@code persona} parameter is set to {@code true}) identified by the specified identifier.
      *
      * @param profileId the identifier of the profile or persona to delete

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/ec58db2c/rest/src/main/java/org/apache/unomi/rest/ProfileServiceEndPoint.java
----------------------------------------------------------------------
diff --git a/rest/src/main/java/org/apache/unomi/rest/ProfileServiceEndPoint.java b/rest/src/main/java/org/apache/unomi/rest/ProfileServiceEndPoint.java
index b806378..038178d 100644
--- a/rest/src/main/java/org/apache/unomi/rest/ProfileServiceEndPoint.java
+++ b/rest/src/main/java/org/apache/unomi/rest/ProfileServiceEndPoint.java
@@ -193,11 +193,13 @@ public class ProfileServiceEndPoint {
     @POST
     @Path("/")
     public Profile save(Profile profile) {
-        // TODO: check that the profile was actually updated correctly before sending the event
-        Event profileUpdated = new Event("profileUpdated", null, profile, null, null, profile, new Date());
-        profileUpdated.setPersistent(false);
-        eventService.send(profileUpdated);
-        return profileService.save(profile);
+        if (profileService.saveOrmerge(profile)) {
+            Event profileUpdated = new Event("profileUpdated", null, profile, null, null, profile, new Date());
+            profileUpdated.setPersistent(false);
+            eventService.send(profileUpdated);
+        }
+
+        return profile;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/ec58db2c/services/src/main/java/org/apache/unomi/services/services/ProfileServiceImpl.java
----------------------------------------------------------------------
diff --git a/services/src/main/java/org/apache/unomi/services/services/ProfileServiceImpl.java b/services/src/main/java/org/apache/unomi/services/services/ProfileServiceImpl.java
index 22e6227..aee8832 100644
--- a/services/src/main/java/org/apache/unomi/services/services/ProfileServiceImpl.java
+++ b/services/src/main/java/org/apache/unomi/services/services/ProfileServiceImpl.java
@@ -17,6 +17,8 @@
 
 package org.apache.unomi.services.services;
 
+import org.apache.commons.beanutils.BeanUtils;
+import org.apache.commons.beanutils.PropertyUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.unomi.api.*;
 import org.apache.unomi.api.conditions.Condition;
@@ -278,12 +280,13 @@ public class ProfileServiceImpl implements ProfileService, SynchronousBundleList
 
     @Override
     public boolean setPropertyType(PropertyType property) {
-        PropertyType previous = null;
-        if ((previous = persistenceService.load(property.getItemId(), PropertyType.class)) != null) {
-            previous.getAutomaticMappingsFrom().addAll(property.getAutomaticMappingsFrom());
-            property = previous;
+        PropertyType previousProperty = persistenceService.load(property.getItemId(), PropertyType.class);
+        if (previousProperty == null) {
+            return persistenceService.save(property);
+        } else if (merge(previousProperty, property)) {
+            return persistenceService.save(previousProperty);
         }
-        return persistenceService.save(property);
+        return false;
     }
 
     @Override
@@ -362,7 +365,7 @@ public class ProfileServiceImpl implements ProfileService, SynchronousBundleList
 
     // TODO may be moved this in a specific Export Utils Class and improve it to handle date format, ...
     private void handleExportProperty(StringBuilder sb, Object propertyValue, PropertyType propertyType) {
-        if (propertyValue instanceof Collection && propertyType != null && propertyType.isMultivalued()) {
+        if (propertyValue instanceof Collection && propertyType != null && propertyType.isMultivalued() != null && propertyType.isMultivalued() ) {
             Collection propertyValues = (Collection) propertyValue;
             Collection encodedValues = new ArrayList(propertyValues.size());
             for (Object value : propertyValues) {
@@ -397,6 +400,17 @@ public class ProfileServiceImpl implements ProfileService, SynchronousBundleList
         return persistenceService.load(profile.getItemId(), Profile.class);
     }
 
+    public boolean saveOrmerge(Profile profile) {
+        Profile previousProfile = persistenceService.load(profile.getItemId(), Profile.class);
+        if (previousProfile == null) {
+            return persistenceService.save(profile);
+        } else if (merge(previousProfile, profile)) {
+            return persistenceService.save(previousProfile);
+        }
+
+        return false;
+    }
+
     public Persona savePersona(Persona profile) {
         if (persistenceService.load(profile.getItemId(), Persona.class) == null) {
             Session session = new PersonaSession(UUID.randomUUID().toString(), profile, new Date());
@@ -736,4 +750,55 @@ public class ProfileServiceImpl implements ProfileService, SynchronousBundleList
         }
     }
 
+    private <T> boolean merge(T target, T object) {
+        if (object != null) {
+            try {
+                Map<String,Object> objectValues = PropertyUtils.describe(object);
+                Map<String,Object> targetValues = PropertyUtils.describe(target);
+                if (merge(targetValues, objectValues)) {
+                    BeanUtils.populate(target, targetValues);
+                    return true;
+                }
+            } catch (ReflectiveOperationException e) {
+                logger.error("Cannot merge properties",e);
+            }
+        }
+        return false;
+    }
+
+    private boolean merge(Map<String,Object> target, Map<String,Object> object) {
+        boolean changed = false;
+        for (Map.Entry<String, Object> previousEntry : object.entrySet()) {
+            if (previousEntry.getValue() != null) {
+                if (previousEntry.getValue() instanceof Collection) {
+                    Collection currentCollection = (Collection) target.get(previousEntry.getKey());
+                    if (currentCollection != null) {
+                        if (!currentCollection.containsAll((Collection) previousEntry.getValue())) {
+                            changed |= currentCollection.addAll((Collection) previousEntry.getValue());
+                        }
+                    } else {
+                        target.put(previousEntry.getKey(), previousEntry.getValue());
+                        changed = true;
+                    }
+                } else if (previousEntry.getValue() instanceof Map) {
+                    Map<String,Object> currentMap = (Map) target.get(previousEntry.getKey());
+                    if (currentMap == null) {
+                        target.put(previousEntry.getKey(), previousEntry.getValue());
+                        changed = true;
+                    } else {
+                        changed |= merge(currentMap, (Map) previousEntry.getValue());
+                    }
+                } else if (previousEntry.getValue().getClass().getPackage().getName().equals("java.lang")) {
+                    if (previousEntry.getValue() != null && !previousEntry.getValue().equals(target.get(previousEntry.getKey()))) {
+                        target.put(previousEntry.getKey(), previousEntry.getValue());
+                        changed = true;
+                    }
+                } else {
+                    changed |= merge(target.get(previousEntry.getKey()), previousEntry.getValue());
+                }
+            }
+        }
+        return changed;
+    }
+
 }