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

jkevan pushed a commit to branch UNOMI-727-adapt-merge-rollover
in repository https://gitbox.apache.org/repos/asf/unomi.git

commit 2d456a67fde9401d7c4a881acff1604d2be857ae
Author: Kevan <ke...@jahia.com>
AuthorDate: Thu Mar 9 19:28:01 2023 +0100

    UNOMI-727: adapt merge system to rollover (and cleanup too)
---
 .../actions/MergeProfilesOnPropertyAction.java     | 269 ++++++++++-----------
 1 file changed, 131 insertions(+), 138 deletions(-)

diff --git 
a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/MergeProfilesOnPropertyAction.java
 
b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/MergeProfilesOnPropertyAction.java
index 2261a2a4b..49d9c7cc7 100644
--- 
a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/MergeProfilesOnPropertyAction.java
+++ 
b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/MergeProfilesOnPropertyAction.java
@@ -24,14 +24,15 @@ import org.apache.unomi.api.Profile;
 import org.apache.unomi.api.Session;
 import org.apache.unomi.api.actions.Action;
 import org.apache.unomi.api.actions.ActionExecutor;
-import org.apache.unomi.api.actions.ActionPostExecutor;
 import org.apache.unomi.api.conditions.Condition;
 import org.apache.unomi.api.services.*;
 import org.apache.unomi.persistence.spi.PersistenceService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.UUID;
 
 public class MergeProfilesOnPropertyAction implements ActionExecutor {
@@ -46,171 +47,163 @@ public class MergeProfilesOnPropertyAction implements 
ActionExecutor {
 
     public int execute(Action action, Event event) {
 
-        Profile profile = event.getProfile();
-        if (profile instanceof Persona || profile.isAnonymousProfile()) {
+        Profile eventProfile = event.getProfile();
+        final String mergePropName = (String) 
action.getParameterValues().get("mergeProfilePropertyName");
+        final String mergePropValue = (String) 
action.getParameterValues().get("mergeProfilePropertyValue");
+        boolean forceEventProfileAsMaster = 
action.getParameterValues().containsKey("forceEventProfileAsMaster") ? 
(boolean) action.getParameterValues().get("forceEventProfileAsMaster") : false;
+        final String currentProfileMergeValue = (String) 
eventProfile.getSystemProperties().get(mergePropName);
+
+        if (eventProfile instanceof Persona || 
eventProfile.isAnonymousProfile() || StringUtils.isEmpty(mergePropName) ||
+                StringUtils.isEmpty(mergePropValue)) {
             return EventService.NO_CHANGE;
         }
 
-        final String mergeProfilePropertyName = (String) 
action.getParameterValues().get("mergeProfilePropertyName");
-        if (StringUtils.isEmpty(mergeProfilePropertyName)) {
-            return EventService.NO_CHANGE;
+        final List<Profile> profilesToBeMerge = 
getProfilesToBeMerge(mergePropName, mergePropValue);
+
+        // Check if the user switched to another profile
+        if (StringUtils.isNotEmpty(currentProfileMergeValue) && 
!currentProfileMergeValue.equals(mergePropValue)) {
+            reassignSession(event, profilesToBeMerge, 
forceEventProfileAsMaster, mergePropName, mergePropValue);
+            return EventService.PROFILE_UPDATED + EventService.SESSION_UPDATED;
         }
 
-        final String mergeProfilePropertyValue = (String) 
action.getParameterValues().get("mergeProfilePropertyValue");
-        if (StringUtils.isEmpty(mergeProfilePropertyValue)) {
-            return EventService.NO_CHANGE;
+        // Store merge prop on current profile
+        boolean profileUpdated = false;
+        if (StringUtils.isEmpty(currentProfileMergeValue)) {
+            profileUpdated = true;
+            eventProfile.getSystemProperties().put(mergePropName, 
mergePropValue);
         }
 
-        final String mergeProfilePreviousPropertyValue = 
profile.getSystemProperties().get(mergeProfilePropertyName) != null ? 
profile.getSystemProperties().get(mergeProfilePropertyName).toString() : "";
+        // If not profiles to merge we are done here.
+        if (profilesToBeMerge.isEmpty()) {
+            return profileUpdated ? EventService.PROFILE_UPDATED : 
EventService.NO_CHANGE;
+        }
 
-        final Session currentSession = event.getSession();
+        // add current Profile to profiles to be merged
+        if (profilesToBeMerge.stream().noneMatch(p -> 
StringUtils.equals(p.getItemId(), eventProfile.getItemId()))) {
+            profilesToBeMerge.add(eventProfile);
+        }
 
-        boolean forceEventProfileAsMaster = 
action.getParameterValues().containsKey("forceEventProfileAsMaster") ?
-                (boolean) 
action.getParameterValues().get("forceEventProfileAsMaster") : false;
+        final String eventProfileId = eventProfile.getItemId();
+        final Profile mergedProfile = 
profileService.mergeProfiles(forceEventProfileAsMaster ? eventProfile : 
profilesToBeMerge.get(0), profilesToBeMerge);
+        final String mergedProfileId = mergedProfile.getItemId();
 
-        // store the profile id in case the merge change it to a previous one
-        String profileId = profile.getItemId();
+        // Profile is still using the same profileId after being merged, no 
need to rewrite exists data, merge is done
+        if (!forceEventProfileAsMaster && 
mergedProfileId.equals(eventProfileId)) {
+            return profileUpdated ? EventService.PROFILE_UPDATED : 
EventService.NO_CHANGE;
+        }
 
-        Condition propertyCondition = new 
Condition(definitionsService.getConditionType("profilePropertyCondition"));
-        propertyCondition.setParameter("comparisonOperator", "equals");
-        propertyCondition.setParameter("propertyName", "systemProperties." + 
mergeProfilePropertyName);
-        propertyCondition.setParameter("propertyValue", 
mergeProfilePropertyValue);
+        // ProfileID changed we have a lot to do
+        // First check for privacy stuff (inherit from previous profile if 
necessary)
+        if (privacyService.isRequireAnonymousBrowsing(eventProfile)) {
+            privacyService.setRequireAnonymousBrowsing(mergedProfileId, true, 
event.getScope());
+        }
+        final boolean anonymousBrowsing = 
privacyService.isRequireAnonymousBrowsing(mergedProfileId);
 
-        final List<Profile> profiles = 
persistenceService.query(propertyCondition, "properties.firstVisit", 
Profile.class, 0, maxProfilesInOneMerge).getList();
+        // Modify current session:
+        if (event.getSession() != null) {
+            event.getSession().setProfile(anonymousBrowsing ? 
privacyService.getAnonymousProfile(mergedProfile) : mergedProfile);
+        }
 
-        // Check if the user switched to another profile
-        if (StringUtils.isNotEmpty(mergeProfilePreviousPropertyValue) && 
!mergeProfilePreviousPropertyValue.equals(mergeProfilePropertyValue)) {
-            if (profiles.size() > 0) {
-                // Take existing profile
-                profile = profiles.get(0);
-            } else {
-                if (forceEventProfileAsMaster) {
-                    profile = event.getProfile();
-                } else {
-                    // Create a new profile
-                    profile = new Profile(UUID.randomUUID().toString());
-                    profile.setProperty("firstVisit", event.getTimeStamp());
+        // Modify current event:
+        event.setProfileId(anonymousBrowsing ? null : mergedProfileId);
+        event.setProfile(mergedProfile);
+
+        event.getActionPostExecutors().add(() -> {
+            try {
+                // Save event, as we changed the profileId of the current event
+                if (event.isPersistent()) {
+                    persistenceService.save(event);
                 }
-                profile.getSystemProperties().put(mergeProfilePropertyName, 
mergeProfilePropertyValue);
-            }
 
-            logger.info("Different users, switch to " + profile.getItemId());
-            // At the end of the merge, we must set the merged profile as 
profile event to process other Actions
-            event.setProfileId(profile.getItemId());
-            event.setProfile(profile);
+                for (Profile profileToBeMerge : profilesToBeMerge) {
+                    String profileToBeMergeId = profileToBeMerge.getItemId();
+                    if (!StringUtils.equals(profileToBeMergeId, 
mergedProfileId)) {
 
-            if (currentSession != null) {
-                currentSession.setProfile(profile);
-                eventService.send(new Event("sessionReassigned", 
currentSession, profile, event.getScope(), event, currentSession,
-                        null, event.getTimeStamp(), false));
-            }
+                        // todo move in update by query + script
+                        List<Session> oldSessions = 
persistenceService.query("profileId", profileToBeMergeId, null, Session.class);
+                        for (Session oldSession : oldSessions) {
+                            if 
(!oldSession.getItemId().equals(event.getSession().getItemId())) {
+                                persistenceService.update(oldSession, 
Session.class, "profileId", anonymousBrowsing ? null : mergedProfileId);
+                            }
+                        }
 
-            return EventService.PROFILE_UPDATED + EventService.SESSION_UPDATED;
-        } else {
-            // Store the merge property identifier in the profile
-            profile.getSystemProperties().put(mergeProfilePropertyName, 
mergeProfilePropertyValue);
+                        // todo move in update by query + script
+                        List<Event> oldEvents = 
persistenceService.query("profileId", profileToBeMergeId, null, Event.class);
+                        for (Event oldEvent : oldEvents) {
+                            if 
(!oldEvent.getItemId().equals(event.getItemId())) {
+                                persistenceService.update(oldEvent, 
Event.class, "profileId", anonymousBrowsing ? null : mergedProfileId);
+                            }
+                        }
 
-            // add current Profile to profiles to be merged
-            boolean add = true;
-            for (Profile p : profiles) {
-                add = add && !StringUtils.equals(p.getItemId(), 
profile.getItemId());
-            }
-            if (add) {
-                profiles.add(profile);
+                        final String clientIdFromEvent = (String) 
event.getAttributes().get(Event.CLIENT_ID_ATTRIBUTE);
+                        String clientId = clientIdFromEvent != null ? 
clientIdFromEvent : "defaultClientId";
+                        profileService.addAliasToProfile(mergedProfileId, 
profileToBeMergeId, clientId);
+                        if (profileService.load(profileToBeMergeId) != null) {
+                            profileService.delete(profileToBeMergeId, false);
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                logger.error("unable to execute callback action, profile and 
session will not be saved", e);
+                return false;
             }
+            return true;
+        });
 
-            if (profiles.size() == 1) {
-                return StringUtils.isEmpty(mergeProfilePreviousPropertyValue) 
? EventService.PROFILE_UPDATED : EventService.NO_CHANGE;
-            }
+        return EventService.PROFILE_UPDATED + EventService.SESSION_UPDATED;
+    }
 
-            Profile markedMasterProfile;
-            if (forceEventProfileAsMaster)
-                markedMasterProfile = event.getProfile();
-            else
-                markedMasterProfile = profiles.get(0);// Use oldest profile 
for master profile
+    private List<Profile> getProfilesToBeMerge(String 
mergeProfilePropertyName, String mergeProfilePropertyValue) {
+        Condition propertyCondition = new 
Condition(definitionsService.getConditionType("profilePropertyCondition"));
+        propertyCondition.setParameter("comparisonOperator", "equals");
+        propertyCondition.setParameter("propertyName", "systemProperties." + 
mergeProfilePropertyName);
+        propertyCondition.setParameter("propertyValue", 
mergeProfilePropertyValue);
 
-            final Profile masterProfile = 
profileService.mergeProfiles(markedMasterProfile, profiles);
+        return persistenceService.query(propertyCondition, 
"properties.firstVisit", Profile.class, 0, maxProfilesInOneMerge).getList();
+    }
 
-            // Profile has changed
-            if (forceEventProfileAsMaster || 
!masterProfile.getItemId().equals(profileId)) {
+    private void reassignSession(Event event, List<Profile> 
existingMergedProfiles, boolean forceEventProfileAsMaster, String 
mergePropName, String mergePropValue) {
+        Profile eventProfile = event.getProfile();
 
-                final String masterProfileId = masterProfile.getItemId();
-                // At the end of the merge, we must set the merged profile as 
profile event to process other Actions
-                event.setProfileId(masterProfileId);
-                event.setProfile(masterProfile);
+        if (existingMergedProfiles.size() > 0) {
+            // Take existing profile
+            eventProfile = existingMergedProfiles.get(0);
+        } else {
+            if (!forceEventProfileAsMaster) {
+                // Create a new profile
+                eventProfile = new Profile(UUID.randomUUID().toString());
+                eventProfile.setProperty("firstVisit", event.getTimeStamp());
+            }
+            eventProfile.getSystemProperties().put(mergePropName, 
mergePropValue);
+        }
 
-                final Boolean anonymousBrowsing = 
privacyService.isRequireAnonymousBrowsing(masterProfileId);
+        logger.info("Different users, switch to " + eventProfile.getItemId());
+        // At the end of the merge, we must set the merged profile as profile 
event to process other Actions
+        event.setProfileId(eventProfile.getItemId());
+        event.setProfile(eventProfile);
 
-                if (currentSession != null) {
-                    currentSession.setProfile(masterProfile);
-                    if (privacyService.isRequireAnonymousBrowsing(profile)) {
-                        
privacyService.setRequireAnonymousBrowsing(masterProfileId, true, 
event.getScope());
-                    }
+        if (event.getSession() != null) {
+            Session eventSession = event.getSession();
+            eventSession.setProfile(eventProfile);
+            eventService.send(new Event("sessionReassigned", eventSession, 
eventProfile, event.getScope(), event, eventSession,
+                    null, event.getTimeStamp(), false));
+        }
+    }
 
-                    if (anonymousBrowsing) {
-                        
currentSession.setProfile(privacyService.getAnonymousProfile(masterProfile));
-                        event.setProfileId(null);
-                        persistenceService.save(event);
-                    }
-                }
+    private void updateAllSessionsForProfile(String newProfileId, String 
oldProfileId) {
+        String[] scripts = new String[]{"updateProfileId"};
 
-                event.getActionPostExecutors().add(new ActionPostExecutor() {
-                    @Override
-                    public boolean execute() {
-                        try {
-                            Event currentEvent = event;
-                            // Update current event explicitly, as it might 
not return from search query if there wasn't a refresh in ES
-                            if (!StringUtils.equals(profileId, 
masterProfileId)) {
-                                if (currentEvent.isPersistent()) {
-                                    persistenceService.update(currentEvent, 
Event.class, "profileId", anonymousBrowsing ? null : masterProfileId);
-                                }
-                            }
+        Map<String, Object>[] scriptParams = new HashMap[1];
+        scriptParams[0] = new HashMap<>();
+        scriptParams[0].put("profileId", newProfileId);
 
-                            for (Profile profile : profiles) {
-                                String profileId = profile.getItemId();
-                                if (!StringUtils.equals(profileId, 
masterProfileId)) {
-                                    // TODO consider udpate by query and/or 
script
-                                    List<Session> sessions = 
persistenceService.query("profileId", profileId, null, Session.class);
-                                    if (currentSession != null) {
-                                        if (masterProfileId.equals(profileId) 
&& !sessions.contains(currentSession)) {
-                                            sessions.add(currentSession);
-                                        }
-                                    }
-
-                                    for (Session session : sessions) {
-                                        persistenceService.update(session, 
Session.class, "profileId", anonymousBrowsing ? null : masterProfileId);
-                                    }
-
-                                    // TODO consider udpate by query and/or 
script
-                                    List<Event> events = 
persistenceService.query("profileId", profileId, null, Event.class);
-                                    for (Event event : events) {
-                                        if 
(!event.getItemId().equals(currentEvent.getItemId())) {
-                                            persistenceService.update(event, 
Event.class, "profileId", anonymousBrowsing ? null : masterProfileId);
-                                        }
-                                    }
-
-                                    final String clientIdFromEvent = (String) 
event.getAttributes().get(Event.CLIENT_ID_ATTRIBUTE);
-                                    String clientId = clientIdFromEvent != 
null ? clientIdFromEvent : "defaultClientId";
-                                    
profileService.addAliasToProfile(masterProfileId, profile.getItemId(), 
clientId);
-
-                                    boolean isExist = 
profileService.load(profile.getItemId()) != null;
-                                    if (isExist) {
-                                        profileService.delete(profileId, 
false);
-                                    }
-                                }
-                            }
-                        } catch (Exception e) {
-                            logger.error("unable to execute callback action, 
profile and session will not be saved", e);
-                            return false;
-                        }
-                        return true;
-                    }
-                });
-                return EventService.PROFILE_UPDATED + 
EventService.SESSION_UPDATED;
-            } else {
-                return StringUtils.isEmpty(mergeProfilePreviousPropertyValue) 
? EventService.PROFILE_UPDATED : EventService.NO_CHANGE;
-            }
-        }
+        Condition[] conditions = new Condition[1];
+        conditions[0] = new Condition();
+        
conditions[0].setConditionType(definitionsService.getConditionType("sessionPropertyCondition"));
+        conditions[0].setParameter("propertyName", "profileId");
+        conditions[0].setParameter("comparisonOperator", "equals");
+        conditions[0].setParameter("propertyValue", oldProfileId);
+        persistenceService.updateWithQueryAndStoredScript(Session.class, 
scripts, scriptParams, conditions);
     }
 
     public void setProfileService(ProfileService profileService) {
@@ -236,4 +229,4 @@ public class MergeProfilesOnPropertyAction implements 
ActionExecutor {
     public void setMaxProfilesInOneMerge(String maxProfilesInOneMerge) {
         this.maxProfilesInOneMerge = Integer.parseInt(maxProfilesInOneMerge);
     }
-}
+}
\ No newline at end of file

Reply via email to