in services/src/main/java/org/apache/unomi/services/impl/profiles/ProfileServiceImpl.java [738:851]
public Profile mergeProfiles(Profile masterProfile, List<Profile> profilesToMerge) {
// now let's remove all the already merged profiles from the list.
List<Profile> filteredProfilesToMerge = new ArrayList<>();
for (Profile filteredProfile : profilesToMerge) {
if (!filteredProfile.getItemId().equals(masterProfile.getItemId())) {
filteredProfilesToMerge.add(filteredProfile);
}
}
if (filteredProfilesToMerge.isEmpty()) {
return masterProfile;
}
profilesToMerge = filteredProfilesToMerge;
Set<String> allProfileProperties = new LinkedHashSet<>();
for (Profile profile : profilesToMerge) {
final Set<String> flatNestedPropertiesKeys = PropertyHelper.flatten(profile.getProperties()).keySet();
allProfileProperties.addAll(flatNestedPropertiesKeys);
}
Collection<PropertyType> profilePropertyTypes = getTargetPropertyTypes("profiles");
Map<String, PropertyType> profilePropertyTypeById = new HashMap<>();
for (PropertyType propertyType : profilePropertyTypes) {
profilePropertyTypeById.put(propertyType.getMetadata().getId(), propertyType);
}
Set<String> profileIdsToMerge = new TreeSet<>();
for (Profile profileToMerge : profilesToMerge) {
profileIdsToMerge.add(profileToMerge.getItemId());
}
LOGGER.info("Merging profiles {} into profile {}", profileIdsToMerge, masterProfile.getItemId());
boolean masterProfileChanged = false;
for (String profileProperty : allProfileProperties) {
PropertyType propertyType = profilePropertyTypeById.get(profileProperty);
String propertyMergeStrategyId = "defaultMergeStrategy";
if (propertyType != null) {
if (propertyType.getMergeStrategy() != null && propertyMergeStrategyId.length() > 0) {
propertyMergeStrategyId = propertyType.getMergeStrategy();
}
}
PropertyMergeStrategyType propertyMergeStrategyType = definitionsService.getPropertyMergeStrategyType(propertyMergeStrategyId);
if (propertyMergeStrategyType == null) {
// we couldn't find the strategy
if (propertyMergeStrategyId.equals("defaultMergeStrategy")) {
LOGGER.warn("Couldn't resolve default strategy, ignoring property merge for property {}", profileProperty);
continue;
} else {
// todo: improper algorithm… it is possible that the defaultMergeStrategy couldn't be resolved here
LOGGER.warn("Couldn't resolve strategy {} for property {}, using default strategy instead", propertyMergeStrategyId,
profileProperty);
propertyMergeStrategyId = "defaultMergeStrategy";
propertyMergeStrategyType = definitionsService.getPropertyMergeStrategyType(propertyMergeStrategyId);
}
}
// todo: find a way to avoid resolving PropertyMergeStrategyExecutor every time?
Collection<ServiceReference<PropertyMergeStrategyExecutor>> matchingPropertyMergeStrategyExecutors;
try {
matchingPropertyMergeStrategyExecutors = bundleContext.getServiceReferences(PropertyMergeStrategyExecutor.class, propertyMergeStrategyType.getFilter());
for (ServiceReference<PropertyMergeStrategyExecutor> propertyMergeStrategyExecutorReference : matchingPropertyMergeStrategyExecutors) {
PropertyMergeStrategyExecutor propertyMergeStrategyExecutor = bundleContext.getService(propertyMergeStrategyExecutorReference);
masterProfileChanged |= propertyMergeStrategyExecutor.mergeProperty(profileProperty, propertyType, profilesToMerge, masterProfile);
}
} catch (InvalidSyntaxException e) {
LOGGER.error("Error retrieving strategy implementation", e);
}
}
// merge System properties
for (Profile profile : profilesToMerge) {
masterProfileChanged = mergeSystemProperties(masterProfile.getSystemProperties(), profile.getSystemProperties()) || masterProfileChanged;
}
// we now have to merge the profile's segments
for (Profile profile : profilesToMerge) {
if (profile.getSegments() != null && !profile.getSegments().isEmpty()) {
masterProfile.getSegments().addAll(profile.getSegments());
// TODO better segments diff calculation
masterProfileChanged = true;
}
}
// we now have to merge the profile's consents
for (Profile profile : profilesToMerge) {
if (profile.getConsents() != null && !profile.getConsents().isEmpty()) {
for (String consentId : profile.getConsents().keySet()) {
if (masterProfile.getConsents().containsKey(consentId)) {
if (masterProfile.getConsents().get(consentId).getRevokeDate().before(new Date())) {
masterProfile.getConsents().remove(consentId);
masterProfileChanged = true;
} else if (masterProfile.getConsents().get(consentId).getStatusDate().before(profile.getConsents().get(consentId).getStatusDate())) {
masterProfile.getConsents().replace(consentId, profile.getConsents().get(consentId));
masterProfileChanged = true;
}
} else {
masterProfile.getConsents().put(consentId, profile.getConsents().get(consentId));
masterProfileChanged = true;
}
}
}
}
if (masterProfileChanged) {
persistenceService.save(masterProfile);
}
return masterProfile;
}