UNOMI-14 : Store merge information in system property . Switch profile id when user already has login information
Project: http://git-wip-us.apache.org/repos/asf/incubator-unomi/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-unomi/commit/8f4c6d01 Tree: http://git-wip-us.apache.org/repos/asf/incubator-unomi/tree/8f4c6d01 Diff: http://git-wip-us.apache.org/repos/asf/incubator-unomi/diff/8f4c6d01 Branch: refs/heads/master Commit: 8f4c6d0110b8fc726f3eee1c37f88945e0520bcb Parents: 27b9459 Author: Thomas Draier <[email protected]> Authored: Tue Feb 2 17:06:35 2016 +0100 Committer: Thomas Draier <[email protected]> Committed: Fri Feb 5 11:32:20 2016 +0100 ---------------------------------------------------------------------- .../actions/MergeProfilesOnPropertyAction.java | 157 ++++++++++++------- .../resources/META-INF/cxs/rules/login.json | 9 +- .../META-INF/cxs/rules/newSession.json | 24 --- .../META-INF/cxs/rules/sessionAssigned.json | 59 +++++++ .../services/services/RulesServiceImpl.java | 6 +- 5 files changed, 165 insertions(+), 90 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/8f4c6d01/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/MergeProfilesOnPropertyAction.java ---------------------------------------------------------------------- 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 9a7c979..64ca3e9 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 @@ -38,6 +38,7 @@ import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import java.util.Arrays; import java.util.List; +import java.util.UUID; public class MergeProfilesOnPropertyAction implements ActionExecutor { @@ -93,26 +94,31 @@ public class MergeProfilesOnPropertyAction implements ActionExecutor { public int execute(Action action, Event event) { - final Profile profile = event.getProfile(); + Profile profile = event.getProfile(); + if (profile instanceof Persona) { + return EventService.NO_CHANGE; + } final String mergeProfilePropertyName = (String) action.getParameterValues().get("mergeProfilePropertyName"); - final String mergeProfilePropertyValue = profile.getProperty(mergeProfilePropertyName) != null ? profile.getProperty(mergeProfilePropertyName).toString() : ""; - final Session currentSession = event.getSession(); - - // store the profile id in case the merge change it to a previous one - - if (profile instanceof Persona) { + if (StringUtils.isEmpty(mergeProfilePropertyName)) { return EventService.NO_CHANGE; } + final String mergeProfilePropertyValue = (String) action.getParameterValues().get("mergeProfilePropertyValue"); if (StringUtils.isEmpty(mergeProfilePropertyValue)) { return EventService.NO_CHANGE; } + + final String mergeProfilePreviousPropertyValue = profile.getSystemProperties().get(mergeProfilePropertyName) != null ? profile.getSystemProperties().get(mergeProfilePropertyName).toString() : ""; + + final Session currentSession = event.getSession(); + + // store the profile id in case the merge change it to a previous one String profileId = profile.getItemId(); Condition propertyCondition = new Condition(definitionsService.getConditionType("eventPropertyCondition")); propertyCondition.setParameter("comparisonOperator", "equals"); - propertyCondition.setParameter("propertyName", mergeProfilePropertyName); + propertyCondition.setParameter("propertyName", "systemProperties." + mergeProfilePropertyName); propertyCondition.setParameter("propertyValue", mergeProfilePropertyValue); Condition excludeMergedProfilesCondition = new Condition(definitionsService.getConditionType("eventPropertyCondition")); @@ -125,66 +131,101 @@ public class MergeProfilesOnPropertyAction implements ActionExecutor { final List<Profile> profiles = persistenceService.query(c, "properties.firstVisit", Profile.class); - // 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); - } + // Check if the user switched to another profile + if (!StringUtils.isEmpty(mergeProfilePreviousPropertyValue) && !mergeProfilePreviousPropertyValue.equals(mergeProfilePropertyValue)) { + if (profiles.size() > 0) { + // Take existing profile + profile = profiles.get(0); + } else { + // Create a new profile + profile = new Profile(UUID.randomUUID().toString()); + profile.setProperty("firstVisit", currentSession.getTimeStamp()); + profile.getSystemProperties().put(mergeProfilePropertyName, mergeProfilePropertyValue); + } - if (profiles.size() == 1) { - return EventService.NO_CHANGE; - } + logger.info("Different users, switch to " + profile.getItemId()); - Profile masterProfile = profileService.mergeProfiles(profiles.get(0), profiles); - - if (!masterProfile.getItemId().equals(profileId)) { HttpServletResponse httpServletResponse = (HttpServletResponse) event.getAttributes().get(Event.HTTP_RESPONSE_ATTRIBUTE); - sendProfileCookie(event.getSession().getProfile(), httpServletResponse); - final String masterProfileId = masterProfile.getItemId(); + sendProfileCookie(profile, httpServletResponse); // 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); - - event.getActionPostExecutors().add(new ActionPostExecutor() { - @Override - public boolean execute() { - try { - for (Profile profile : profiles) { - String profileId = profile.getItemId(); - if (!StringUtils.equals(profileId, masterProfileId)) { - List<Session> sessions = persistenceService.query("profileId", profileId, null, Session.class); - if (currentSession.getProfileId().equals(profileId) && !sessions.contains(currentSession)) { - sessions.add(currentSession); - } - for (Session session : sessions) { - persistenceService.update(session.getItemId(), session.getTimeStamp(), Session.class, "profileId", masterProfileId); + event.setProfileId(profile.getItemId()); + event.setProfile(profile); + + event.getSession().setProfile(profile); + + eventService.send(new Event("sessionReassigned", event.getSession(), profile, event.getScope(), event, event.getSession(), event.getTimeStamp())); + + return EventService.PROFILE_UPDATED + EventService.SESSION_UPDATED; + } else { + // Store the merge property identifier in the profile + profile.getSystemProperties().put(mergeProfilePropertyName, mergeProfilePropertyValue); + + // 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); + } + + if (profiles.size() == 1) { + return StringUtils.isEmpty(mergeProfilePreviousPropertyValue) ? EventService.PROFILE_UPDATED : EventService.NO_CHANGE; + } + + // Use oldest profile for master profile + Profile masterProfile = profileService.mergeProfiles(profiles.get(0), profiles); + + // Profile has changed + if (!masterProfile.getItemId().equals(profileId)) { + HttpServletResponse httpServletResponse = (HttpServletResponse) event.getAttributes().get(Event.HTTP_RESPONSE_ATTRIBUTE); + sendProfileCookie(event.getSession().getProfile(), httpServletResponse); + 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); + + event.getSession().setProfile(masterProfile); + + event.getActionPostExecutors().add(new ActionPostExecutor() { + @Override + public boolean execute() { + try { + for (Profile profile : profiles) { + String profileId = profile.getItemId(); + if (!StringUtils.equals(profileId, masterProfileId)) { + List<Session> sessions = persistenceService.query("profileId", profileId, null, Session.class); + if (currentSession.getProfileId().equals(profileId) && !sessions.contains(currentSession)) { + sessions.add(currentSession); + } + for (Session session : sessions) { + persistenceService.update(session.getItemId(), session.getTimeStamp(), Session.class, "profileId", masterProfileId); + } + + List<Event> events = persistenceService.query("profileId", profileId, null, Event.class); + for (Event event : events) { + persistenceService.update(event.getItemId(), event.getTimeStamp(), Event.class, "profileId", masterProfileId); + } + // we must mark all the profiles that we merged into the master as merged with the master, and they will + // be deleted upon next load + profile.setMergedWith(masterProfileId); + persistenceService.update(profile.getItemId(), null, Profile.class, "mergedWith", masterProfileId); } - - List<Event> events = persistenceService.query("profileId", profileId, null, Event.class); - for (Event event : events) { - persistenceService.update(event.getItemId(), event.getTimeStamp(), Event.class, "profileId", masterProfileId); - } - // we must mark all the profiles that we merged into the master as merged with the master, and they will - // be deleted upon next load - profile.setMergedWith(masterProfileId); - persistenceService.update(profile.getItemId(), null, Profile.class, "mergedWith", masterProfileId); } + } catch (Exception e) { + logger.error("unable to execute callback action, profile and session will not be saved", e); + return false; } - } catch (Exception e) { - logger.error("unable to execute callback action, profile and session will not be saved", e); - return false; + return true; } - return true; - } - }); - return EventService.PROFILE_UPDATED; + }); + return EventService.PROFILE_UPDATED + EventService.SESSION_UPDATED; + } else { + return StringUtils.isEmpty(mergeProfilePreviousPropertyValue) ? EventService.PROFILE_UPDATED : EventService.NO_CHANGE; + } } - - return EventService.NO_CHANGE; } public void sendProfileCookie(Profile profile, ServletResponse response) { http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/8f4c6d01/plugins/baseplugin/src/main/resources/META-INF/cxs/rules/login.json ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/resources/META-INF/cxs/rules/login.json b/plugins/baseplugin/src/main/resources/META-INF/cxs/rules/login.json index 6ef3caa..de61572 100644 --- a/plugins/baseplugin/src/main/resources/META-INF/cxs/rules/login.json +++ b/plugins/baseplugin/src/main/resources/META-INF/cxs/rules/login.json @@ -21,15 +21,16 @@ "actions": [ { "parameterValues": { - + "mergeProfilePropertyValue": "eventProperty::target.properties(j:nodename)", + "mergeProfilePropertyName": "mergeIdentifier" }, - "type": "allEventToProfilePropertiesAction" + "type": "mergeProfilesOnPropertyAction" }, { "parameterValues": { - "mergeProfilePropertyName": "j:nodename" + }, - "type": "mergeProfilesOnPropertyAction" + "type": "allEventToProfilePropertiesAction" } ] } http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/8f4c6d01/plugins/baseplugin/src/main/resources/META-INF/cxs/rules/newSession.json ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/resources/META-INF/cxs/rules/newSession.json b/plugins/baseplugin/src/main/resources/META-INF/cxs/rules/newSession.json index 12bf580..6eca16e 100644 --- a/plugins/baseplugin/src/main/resources/META-INF/cxs/rules/newSession.json +++ b/plugins/baseplugin/src/main/resources/META-INF/cxs/rules/newSession.json @@ -24,30 +24,6 @@ "requestHeaderName": "User-Agent", "sessionPropertyName": "userAgent" } - }, - { - "parameterValues": { - "setPropertyName": "properties.previousVisit", - "setPropertyValue": "profileProperty::lastVisit", - "storeInSession": false - }, - "type": "setPropertyAction" - }, - { - "parameterValues": { - "setPropertyName": "properties.lastVisit", - "setPropertyValue": "now", - "storeInSession": false - }, - "type": "setPropertyAction" - }, - { - "parameterValues": { - "setPropertyName": "properties.nbOfVisits", - "setPropertyValue": "script::profile.properties.?nbOfVisits != null ? (profile.properties.nbOfVisits + 1) : 1", - "storeInSession": false - }, - "type": "setPropertyAction" } ] http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/8f4c6d01/plugins/baseplugin/src/main/resources/META-INF/cxs/rules/sessionAssigned.json ---------------------------------------------------------------------- diff --git a/plugins/baseplugin/src/main/resources/META-INF/cxs/rules/sessionAssigned.json b/plugins/baseplugin/src/main/resources/META-INF/cxs/rules/sessionAssigned.json new file mode 100644 index 0000000..9603b81 --- /dev/null +++ b/plugins/baseplugin/src/main/resources/META-INF/cxs/rules/sessionAssigned.json @@ -0,0 +1,59 @@ +{ + "metadata": { + "id": "_ajhg9u2s5_sessionAssigned", + "name": "Session assigned to a profile", + "description": "Update profile visit information", + "readOnly":true + }, + + "condition": { + "type": "booleanCondition", + "parameterValues": { + "subConditions":[ + { + "type": "eventTypeCondition", + "parameterValues": { + "eventTypeId": "sessionCreated" + } + }, + { + "type": "eventTypeCondition", + "parameterValues": { + "eventTypeId": "sessionReassigned" + } + } + + ], + "operator":"or" + + } + }, + + "actions": [ + { + "parameterValues": { + "setPropertyName": "properties.previousVisit", + "setPropertyValue": "profileProperty::lastVisit", + "storeInSession": false + }, + "type": "setPropertyAction" + }, + { + "parameterValues": { + "setPropertyName": "properties.lastVisit", + "setPropertyValue": "now", + "storeInSession": false + }, + "type": "setPropertyAction" + }, + { + "parameterValues": { + "setPropertyName": "properties.nbOfVisits", + "setPropertyValue": "script::profile.properties.?nbOfVisits != null ? (profile.properties.nbOfVisits + 1) : 1", + "storeInSession": false + }, + "type": "setPropertyAction" + } + ] + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/8f4c6d01/services/src/main/java/org/apache/unomi/services/services/RulesServiceImpl.java ---------------------------------------------------------------------- diff --git a/services/src/main/java/org/apache/unomi/services/services/RulesServiceImpl.java b/services/src/main/java/org/apache/unomi/services/services/RulesServiceImpl.java index 09cd0ec..aa25111 100644 --- a/services/src/main/java/org/apache/unomi/services/services/RulesServiceImpl.java +++ b/services/src/main/java/org/apache/unomi/services/services/RulesServiceImpl.java @@ -192,16 +192,14 @@ public class RulesServiceImpl implements RulesService, EventListenerService, Syn while (predefinedRuleEntries.hasMoreElements()) { URL predefinedSegmentURL = predefinedRuleEntries.nextElement(); - logger.debug("Found predefined segment at " + predefinedSegmentURL + ", loading... "); + logger.debug("Found predefined rule at " + predefinedSegmentURL + ", loading... "); try { Rule rule = CustomObjectMapper.getObjectMapper().readValue(predefinedSegmentURL, Rule.class); if (rule.getMetadata().getScope() == null) { rule.getMetadata().setScope("systemscope"); } - if (getRule(rule.getMetadata().getId()) == null) { - setRule(rule); - } + setRule(rule); } catch (IOException e) { logger.error("Error while loading segment definition " + predefinedSegmentURL, e); }
