diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/Util.java b/java/com.sap.sse.common/src/com/sap/sse/common/Util.java index dd8a03dffb3..42d6092bff5 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/Util.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/Util.java @@ -364,6 +364,12 @@ public class Util { } map.get(key).add(value); } + + public static void removeFromAllValueSets(Map> map, V value) { + for (Set set : map.values()) { + set.remove(value); + } + } public static String join(String separator, String... strings) { return joinStrings(separator, Arrays.asList(strings)); diff --git a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java index 4237f395c2c..f9f94bec1e4 100644 --- a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java +++ b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java @@ -1,7 +1,11 @@ package com.sap.sse.security.userstore.mongodb; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; @@ -12,7 +16,9 @@ import java.util.logging.Logger; import org.apache.shiro.SecurityUtils; +import com.sap.sse.common.Util; import com.sap.sse.security.PreferenceConverter; +import com.sap.sse.security.PreferenceObjectListener; import com.sap.sse.security.SocialSettingsKeys; import com.sap.sse.security.User; import com.sap.sse.security.UserStore; @@ -62,6 +68,8 @@ public class UserStoreImpl implements UserStore { */ private final ConcurrentHashMap> preferenceObjects; + private transient Map>> listeners; + /** * Won't be serialized and remains null on the de-serializing end. */ @@ -81,6 +89,7 @@ public class UserStoreImpl implements UserStore { preferences = new ConcurrentHashMap<>(); preferenceConverters = new ConcurrentHashMap<>(); preferenceObjects = new ConcurrentHashMap<>(); + listeners = new HashMap<>(); this.mongoObjectFactory = mongoObjectFactory; if (domainObjectFactory != null) { for (Entry> e : domainObjectFactory.loadSettingTypes().entrySet()) { @@ -117,6 +126,15 @@ public class UserStoreImpl implements UserStore { } } } + + private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { + ois.defaultReadObject(); + listeners = new HashMap<>(); + } + + private void writeObject(ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + } @Override public void clear() { @@ -538,13 +556,15 @@ public class UserStoreImpl implements UserStore { } } } - userMap.put(key, convertedObject); + Object oldPreference = userMap.put(key, convertedObject); + notifyListenersOnPreferenceObjectChange(username, key, oldPreference, convertedObject); } private void unsetPreferenceObject(String username, String key) { Map userObjectMap = preferenceObjects.get(username); if (userObjectMap != null) { - userObjectMap.remove(key); + Object oldPreference = userObjectMap.remove(key); + notifyListenersOnPreferenceObjectChange(username, key, oldPreference, null); } } @@ -583,4 +603,45 @@ public class UserStoreImpl implements UserStore { } } } + + private void notifyListenersOnPreferenceObjectChange(String username, String key, Object oldPreference, + Object newPreference) { + synchronized (listeners) { + for (PreferenceObjectListener listener : Util.get(listeners, key, + Collections.> emptySet())) { + @SuppressWarnings("unchecked") + PreferenceObjectListener listenerToFire = (PreferenceObjectListener) listener; + listenerToFire.preferenceObjectChanged(username, key, oldPreference, newPreference); + } + } + } + + @Override + public void addPreferenceObjectListener(String key, PreferenceObjectListener listener, + boolean fireForAlreadyExistingPreferences) { + synchronized (listeners) { + Util.addToValueSet(listeners, key, listener); + if (fireForAlreadyExistingPreferences) { + final Set usersToProcess = new HashSet<>(preferences.keySet()); + for (String username : usersToProcess) { + Map userMap = preferenceObjects.get(username); + if (userMap != null) { + Object preferenceObject = userMap.get(key); + if (preferenceObject != null) { + @SuppressWarnings("unchecked") + PreferenceObjectListener listenerToFire = (PreferenceObjectListener) listener; + listenerToFire.preferenceObjectChanged(username, key, null, preferenceObject); + } + } + } + } + } + } + + @Override + public void removePreferenceObjectListener(PreferenceObjectListener listener) { + synchronized (listeners) { + Util.removeFromAllValueSets(listeners, listener); + } + } } diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java b/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java index b08ba8c9fe8..b47c7227075 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java @@ -130,4 +130,8 @@ public interface UserStore extends Named { * {@code username} no access token has previously been {@link #setAccessToken(String, String) set}. */ String getAccessToken(String username); + + void addPreferenceObjectListener(String key, PreferenceObjectListener listener, boolean fireForAlreadyExistingPreferences); + + void removePreferenceObjectListener(PreferenceObjectListener listener); }